From d6ca1b16de863598319fa8d5de157755a1a5143a Mon Sep 17 00:00:00 2001 From: elliotdotsol Date: Wed, 18 Mar 2026 18:06:34 +0700 Subject: [PATCH 01/12] feat: rewrite WebSocket layer with AsyncAPI-driven room-based protocol MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the ad-hoc WS implementation with a typed, room-based protocol derived from the AsyncAPI spec. Types are auto-generated and rooms are validated by check-routes, matching the existing REST/webhook pattern. - Generic `subscribe(room, filters?)` / `unsubscribe(room)` with typed overloads (filters optional only for rooms where spec allows it) - `connect()` returns Promise, `subscribe()` returns Promise with server ack (rejected filters, timeout handling) - `on()` returns disposer function for ergonomic React/framework cleanup - `removeAllListeners()` for bulk teardown - Configurable `subscribeTimeout` via StructWebSocketConfig - Auto-ping keepalive (30s), replay subscriptions on reconnect - AsyncAPI spec pipeline: fetch → generate types → check rooms/schemas - 9 rooms: trades, asset_prices, asset_window_updates, market_metrics, event_metrics, position_metrics, trader_pnl, accounts, order_book Co-Authored-By: Claude Opus 4.6 (1M context) --- CLAUDE.md | 9 +- openapi/ws.json | 1742 ++++++++++++++++++++++++++++++++++ package.json | 6 +- scripts/check-routes.ts | 68 +- scripts/generate-ws-types.ts | 18 + src/generated/ws.ts | 399 ++++++++ src/types/index.ts | 50 +- src/types/ws-helpers.ts | 3 + src/types/ws.ts | 177 ++-- src/ws-transport.ts | 62 +- src/ws.ts | 309 +++--- 11 files changed, 2532 insertions(+), 311 deletions(-) create mode 100644 openapi/ws.json create mode 100644 scripts/generate-ws-types.ts create mode 100644 src/generated/ws.ts create mode 100644 src/types/ws-helpers.ts diff --git a/CLAUDE.md b/CLAUDE.md index bd4941c..851cbd3 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -17,6 +17,8 @@ TypeScript SDK (`@structbuild/sdk`) for prediction market APIs via `api.struct.t - **Check routes:** `bun run check-routes` (validates namespace routes match OpenAPI spec) - **Fetch webhook spec:** `bun run fetch-spec:webhooks` - **Generate webhook types:** `bun run generate:webhooks` +- **Fetch WS spec:** `bun run fetch-spec:ws` (AsyncAPI format) +- **Generate WS types:** `bun run generate:ws` - **Fix spec:** `bun run fix-spec` (fixes broken `$ref`s in the OpenAPI spec) - **Test:** `bun test` (integration tests against live API, requires `STRUCT_API_KEY`) - **Test watch:** `bun test --watch` @@ -29,11 +31,12 @@ TypeScript SDK (`@structbuild/sdk`) for prediction market APIs via `api.struct.t - `src/http.ts` — Generic `HttpClient` built on `fetch` with timeout via `AbortController`, query param building, exponential backoff retry (429/5xx), request/response hooks, and typed `HttpResponse` responses. - `src/errors.ts` — Error hierarchy: `StructError` → `HttpError` | `NetworkError` | `TimeoutError` | `WebSocketError` | `WebSocketClosedError`. - `src/paginate.ts` — `paginate()` async generator for offset-based pagination across any namespace method. -- `src/ws.ts` — `StructWebSocket` for real-time trade streaming. Event system (`on`/`off`/`once`), subscriptions (markets, positions, wallets, conditions, whale/smart-money/insider rooms), auto-replays subscriptions on reconnect. -- `src/ws-transport.ts` — Low-level WebSocket connection management with reconnection (exponential backoff + jitter), pending/replay message queues. -- `src/types/` — All type definitions. `common.ts` (pagination/sort/Venue), `helpers.ts` (OpenAPI type utilities: `OperationQuery`, `OperationPath`, `OperationResponse`), `webhook-helpers.ts` (webhook OpenAPI type utilities), `http.ts` (client config/request/response), `ws.ts` (WebSocket types). `index.ts` barrel exports all types. +- `src/ws.ts` — `StructWebSocket` for real-time streaming. Room-based protocol (`join_room`/`room_message`). Generic typed `subscribe(room, filters?)` / `unsubscribe(room)` with Promise-based acks. Event system (`on`/`off`/`once`/`removeAllListeners`), `on()` returns disposer function. Auto-replays subscriptions on reconnect, keepalive ping. +- `src/ws-transport.ts` — Low-level WebSocket connection management with reconnection (exponential backoff + jitter), pending/replay message queues. `connect()` returns `Promise`. +- `src/types/` — All type definitions. `common.ts` (pagination/sort/Venue), `helpers.ts` (OpenAPI type utilities: `OperationQuery`, `OperationPath`, `OperationResponse`), `webhook-helpers.ts` (webhook OpenAPI type utilities), `ws-helpers.ts` (WS type utilities: `WsSchemas`), `http.ts` (client config/request/response), `ws.ts` (WebSocket types: room IDs, subscribe filters, event types, event map, subscription/response maps). `index.ts` barrel exports all types. - `src/generated/polymarket.ts` — Auto-generated types from the Polymarket OpenAPI spec via `openapi-typescript`. Do not edit manually. - `src/generated/webhooks.ts` — Auto-generated types from the Webhooks OpenAPI spec. Do not edit manually. +- `src/generated/ws.ts` — Auto-generated types from the WS AsyncAPI spec (`scripts/generate-ws-types.ts`). Do not edit manually. - `src/index.ts` — Public barrel export. - `tests/integration.test.ts` — Auto-discovers namespace methods and runs them against the live API. Test config in `tests/integration.meta.ts` defines params and operationId mappings per method. diff --git a/openapi/ws.json b/openapi/ws.json new file mode 100644 index 0000000..34199ee --- /dev/null +++ b/openapi/ws.json @@ -0,0 +1,1742 @@ +{ + "asyncapi": "3.0.0", + "info": { + "title": "Polymarket WebSocket API", + "version": "1.0.0", + "description": "Real-time WebSocket streaming API for Polymarket prediction-market data.\n\n## Connection\nConnect to `wss://api.struct.to/ws` using a standard WebSocket client.\n\n## Authentication\nAfter connecting, send:\n```json\n{\"type\":\"authenticate\",\"jwt\":\"\"}\n```\nUnauthenticated connections can read public rooms but credit checks are enforced.\n\n## Joining a room\n```json\n{\"type\":\"join_room\",\"payload\":{\"room_id\":\"polymarket_trades\"}}\n```\n\n## Subscribing\nAfter joining, send a `room_message` with room-specific subscribe payload:\n```json\n{\n\"type\": \"room_message\",\n\"payload\": {\n\"room_id\": \"polymarket_trades\",\n\"message\": {\"action\":\"subscribe\",\"condition_ids\":[\"0xabc…\"]}\n}\n}\n```\n\n## Keepalive\nThe server expects a `{\"type\":\"ping\"}` or WebSocket ping frame at least every 60 seconds." + }, + "servers": { + "production": { + "host": "api.struct.to", + "pathname": "/ws", + "protocol": "wss", + "description": "Production WebSocket endpoint" + } + }, + "channels": { + "polymarket_trades": { + "address": "polymarket_trades", + "title": "Trades", + "summary": "Trades stream", + "description": "Real-time stream of matched Polymarket prediction-market trades. At least one filter is required — open-ended subscriptions are rejected to prevent fan-out across all trades.\n\n**Filters (at least one required):**\n- `condition_ids` — 64-char hex condition IDs (with or without `0x` prefix)\n- `market_slugs` — market slugs\n- `event_slugs` — event slugs (delivers all markets under each event)\n- `position_ids` — ERC-1155 token IDs (decimal or hex)\n\n**Unsubscribe:** Send `action: \"unsubscribe_all\"` to clear all subscriptions.", + "messages": { + "subscribe": { + "$ref": "#/components/messages/TradesStreamSubscribe" + }, + "tradeStreamEvent": { + "$ref": "#/components/messages/TradeStreamEvent" + } + } + }, + "polymarket_asset_prices": { + "address": "polymarket_asset_prices", + "title": "Asset Prices", + "summary": "Asset prices stream", + "description": "Real-time crypto-asset price feed (BTC, ETH, SOL, XRP, …). Delivers both raw `asset_price_tick` events on every price update and `asset_price_window_update` events at candle open/close boundaries.\n\n**Filter (optional):** `asset_symbols` — uppercase symbols to filter by. Empty array subscribes to all symbols.\n\n**Unsubscribe:** Send `action: \"unsubscribe_all\"`.", + "messages": { + "subscribe": { + "$ref": "#/components/messages/AssetPricesSubscribe" + }, + "assetPriceTickEvent": { + "$ref": "#/components/messages/AssetPriceTickEvent" + }, + "assetPriceWindowUpdateEvent": { + "$ref": "#/components/messages/AssetPriceWindowUpdateEvent" + } + } + }, + "polymarket_asset_window_updates": { + "address": "polymarket_asset_window_updates", + "title": "Asset Window Updates", + "summary": "Asset window updates stream", + "description": "Filtered stream of asset-price candle open/close events. Unlike `polymarket_asset_prices`, this room **requires** at least one filter so clients receive only the symbols and/or timeframes they care about.\n\n**Filters (at least one required):**\n- `asset_symbols` — uppercase symbols (e.g. `\"BTC\"`, `\"ETH\"`)\n- `timeframes` — candle sizes: `\"5m\"`, `\"15m\"`, `\"1h\"`, `\"4h\"`, `\"1d\"` / `\"24h\"`\n\n**Unsubscribe:** Send `action: \"unsubscribe_all\"`.", + "messages": { + "subscribe": { + "$ref": "#/components/messages/AssetWindowUpdatesSubscribe" + }, + "assetWindowUpdateEvent": { + "$ref": "#/components/messages/AssetWindowUpdateEvent" + } + } + }, + "polymarket_market_metrics": { + "address": "polymarket_market_metrics", + "title": "Market Metrics", + "summary": "Market (condition) metrics stream", + "description": "Real-time volume and transaction-count metrics per market condition, aggregated across multiple timeframes (`1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`).\n\n**Filter (required):** `condition_ids` — 64-char hex condition IDs. Invalid or malformed IDs are returned in `rejected`.\n\n**Unsubscribe:** Send `action: \"unsubscribe_all\"`.", + "messages": { + "subscribe": { + "$ref": "#/components/messages/MarketMetricsSubscribe" + }, + "marketMetricsEvent": { + "$ref": "#/components/messages/MarketMetricsEvent" + } + } + }, + "polymarket_event_metrics": { + "address": "polymarket_event_metrics", + "title": "Event Metrics", + "summary": "Event metrics stream", + "description": "Real-time volume and transaction-count metrics aggregated at the event (parent market group) level, across multiple timeframes.\n\n**Filter (required):** `event_slugs` — event slugs (lowercase).\n\n**Unsubscribe:** Send `action: \"unsubscribe_all\"`.", + "messages": { + "subscribe": { + "$ref": "#/components/messages/EventMetricsSubscribe" + }, + "eventMetricsEvent": { + "$ref": "#/components/messages/EventMetricsEvent" + } + } + }, + "polymarket_position_metrics": { + "address": "polymarket_position_metrics", + "title": "Position Metrics", + "summary": "Position (outcome token) metrics stream", + "description": "Real-time volume and transaction-count metrics per outcome-token position, across multiple timeframes.\n\n**Filter (required):** `position_ids` — ERC-1155 token IDs (decimal or hex; normalized to decimal strings internally).\n\n**Unsubscribe:** Send `action: \"unsubscribe_all\"`.", + "messages": { + "subscribe": { + "$ref": "#/components/messages/PositionMetricsSubscribe" + }, + "positionMetricsEvent": { + "$ref": "#/components/messages/PositionMetricsEvent" + } + } + }, + "polymarket_trader_pnl": { + "address": "polymarket_trader_pnl", + "title": "Trader PnL", + "summary": "Trader PnL stream", + "description": "Real-time profit-and-loss updates for tracked traders, delivered at global, market (condition), and event granularity.\n\n**Filter (required):** `traders` — EVM wallet addresses. Invalid addresses are returned in `rejected`.\n\n**Events pushed:** `trader_global_pnl_update`, `trader_market_pnl_update`, `trader_event_pnl_update`.\n\n**Unsubscribe:** Send `action: \"unsubscribe_all\"`.", + "messages": { + "subscribe": { + "$ref": "#/components/messages/TraderPnlSubscribe" + }, + "traderGlobalPnlEvent": { + "$ref": "#/components/messages/TraderGlobalPnlEvent" + }, + "traderMarketPnlEvent": { + "$ref": "#/components/messages/TraderMarketPnlEvent" + }, + "traderEventPnlEvent": { + "$ref": "#/components/messages/TraderEventPnlEvent" + } + } + }, + "polymarket_accounts": { + "address": "polymarket_accounts", + "title": "Accounts", + "summary": "Account balances stream", + "description": "Real-time balance updates for Polymarket wallet accounts.\n\nAlways streams ERC-1155 outcome token (shares) balance changes for subscribed wallets as `accounts_update` events. Opt in to additional token streams via boolean flags:\n- `include_usdce: true` — also receive `usdce_update` events (USDCe collateral balance)\n- `include_matic: true` — also receive `matic_update` events (MATIC gas balance)\n\n**Filter (required):** `wallets` — EVM wallet addresses. Invalid addresses are returned in `rejected`.\n\n**Unsubscribe:** Send `action: \"unsubscribe_all\"`.", + "messages": { + "subscribe": { + "$ref": "#/components/messages/AccountsSubscribe" + }, + "accountsUpdateEvent": { + "$ref": "#/components/messages/AccountsUpdateEvent" + }, + "usdceUpdateEvent": { + "$ref": "#/components/messages/UsdceUpdateEvent" + }, + "maticUpdateEvent": { + "$ref": "#/components/messages/MaticUpdateEvent" + } + } + }, + "polymarket_order_book": { + "address": "polymarket_order_book", + "title": "Order Book", + "summary": "Order book snapshots stream", + "description": "Real-time CLOB orderbook snapshots for Polymarket outcome tokens. Each event contains the full aggregated bid/ask book plus pre-computed derived metrics (best bid/ask, mid price, spread, USD liquidity depth, level counts).\n\n**Filters (at least one required, max 500 combined):**\n- `condition_ids` — 64-char hex condition IDs (market); delivers snapshots for all positions in that market\n- `position_ids` — hex token/asset IDs (individual outcome tokens)\n\n**Unsubscribe:** Send `action: \"unsubscribe_all\"`.", + "messages": { + "subscribe": { + "$ref": "#/components/messages/OrderBookSubscribe" + }, + "orderBookUpdateEvent": { + "$ref": "#/components/messages/OrderBookUpdateEvent" + } + } + } + }, + "operations": { + "subscribePolymarketTrades": { + "action": "send", + "channel": { + "$ref": "#/channels/polymarket_trades" + }, + "summary": "Subscribe to trades stream", + "messages": [ + { + "$ref": "#/channels/polymarket_trades/messages/subscribe" + } + ] + }, + "receivePolymarketTrades": { + "action": "receive", + "channel": { + "$ref": "#/channels/polymarket_trades" + }, + "summary": "Receive trades stream events", + "messages": [ + { + "$ref": "#/channels/polymarket_trades/messages/tradeStreamEvent" + } + ] + }, + "subscribePolymarketAssetPrices": { + "action": "send", + "channel": { + "$ref": "#/channels/polymarket_asset_prices" + }, + "summary": "Subscribe to asset prices stream", + "messages": [ + { + "$ref": "#/channels/polymarket_asset_prices/messages/subscribe" + } + ] + }, + "receivePolymarketAssetPrices": { + "action": "receive", + "channel": { + "$ref": "#/channels/polymarket_asset_prices" + }, + "summary": "Receive asset prices stream events", + "messages": [ + { + "$ref": "#/channels/polymarket_asset_prices/messages/assetPriceTickEvent" + }, + { + "$ref": "#/channels/polymarket_asset_prices/messages/assetPriceWindowUpdateEvent" + } + ] + }, + "subscribePolymarketAssetWindowUpdates": { + "action": "send", + "channel": { + "$ref": "#/channels/polymarket_asset_window_updates" + }, + "summary": "Subscribe to asset window updates stream", + "messages": [ + { + "$ref": "#/channels/polymarket_asset_window_updates/messages/subscribe" + } + ] + }, + "receivePolymarketAssetWindowUpdates": { + "action": "receive", + "channel": { + "$ref": "#/channels/polymarket_asset_window_updates" + }, + "summary": "Receive asset window updates stream events", + "messages": [ + { + "$ref": "#/channels/polymarket_asset_window_updates/messages/assetWindowUpdateEvent" + } + ] + }, + "subscribePolymarketMarketMetrics": { + "action": "send", + "channel": { + "$ref": "#/channels/polymarket_market_metrics" + }, + "summary": "Subscribe to market (condition) metrics stream", + "messages": [ + { + "$ref": "#/channels/polymarket_market_metrics/messages/subscribe" + } + ] + }, + "receivePolymarketMarketMetrics": { + "action": "receive", + "channel": { + "$ref": "#/channels/polymarket_market_metrics" + }, + "summary": "Receive market (condition) metrics stream events", + "messages": [ + { + "$ref": "#/channels/polymarket_market_metrics/messages/marketMetricsEvent" + } + ] + }, + "subscribePolymarketEventMetrics": { + "action": "send", + "channel": { + "$ref": "#/channels/polymarket_event_metrics" + }, + "summary": "Subscribe to event metrics stream", + "messages": [ + { + "$ref": "#/channels/polymarket_event_metrics/messages/subscribe" + } + ] + }, + "receivePolymarketEventMetrics": { + "action": "receive", + "channel": { + "$ref": "#/channels/polymarket_event_metrics" + }, + "summary": "Receive event metrics stream events", + "messages": [ + { + "$ref": "#/channels/polymarket_event_metrics/messages/eventMetricsEvent" + } + ] + }, + "subscribePolymarketPositionMetrics": { + "action": "send", + "channel": { + "$ref": "#/channels/polymarket_position_metrics" + }, + "summary": "Subscribe to position (outcome token) metrics stream", + "messages": [ + { + "$ref": "#/channels/polymarket_position_metrics/messages/subscribe" + } + ] + }, + "receivePolymarketPositionMetrics": { + "action": "receive", + "channel": { + "$ref": "#/channels/polymarket_position_metrics" + }, + "summary": "Receive position (outcome token) metrics stream events", + "messages": [ + { + "$ref": "#/channels/polymarket_position_metrics/messages/positionMetricsEvent" + } + ] + }, + "subscribePolymarketTraderPnl": { + "action": "send", + "channel": { + "$ref": "#/channels/polymarket_trader_pnl" + }, + "summary": "Subscribe to trader pnl stream", + "messages": [ + { + "$ref": "#/channels/polymarket_trader_pnl/messages/subscribe" + } + ] + }, + "receivePolymarketTraderPnl": { + "action": "receive", + "channel": { + "$ref": "#/channels/polymarket_trader_pnl" + }, + "summary": "Receive trader pnl stream events", + "messages": [ + { + "$ref": "#/channels/polymarket_trader_pnl/messages/traderGlobalPnlEvent" + }, + { + "$ref": "#/channels/polymarket_trader_pnl/messages/traderMarketPnlEvent" + }, + { + "$ref": "#/channels/polymarket_trader_pnl/messages/traderEventPnlEvent" + } + ] + }, + "subscribePolymarketAccounts": { + "action": "send", + "channel": { + "$ref": "#/channels/polymarket_accounts" + }, + "summary": "Subscribe to account balances stream", + "messages": [ + { + "$ref": "#/channels/polymarket_accounts/messages/subscribe" + } + ] + }, + "receivePolymarketAccounts": { + "action": "receive", + "channel": { + "$ref": "#/channels/polymarket_accounts" + }, + "summary": "Receive account balances stream events", + "messages": [ + { + "$ref": "#/channels/polymarket_accounts/messages/accountsUpdateEvent" + }, + { + "$ref": "#/channels/polymarket_accounts/messages/usdceUpdateEvent" + }, + { + "$ref": "#/channels/polymarket_accounts/messages/maticUpdateEvent" + } + ] + }, + "subscribePolymarketOrderBook": { + "action": "send", + "channel": { + "$ref": "#/channels/polymarket_order_book" + }, + "summary": "Subscribe to order book snapshots stream", + "messages": [ + { + "$ref": "#/channels/polymarket_order_book/messages/subscribe" + } + ] + }, + "receivePolymarketOrderBook": { + "action": "receive", + "channel": { + "$ref": "#/channels/polymarket_order_book" + }, + "summary": "Receive order book snapshots stream events", + "messages": [ + { + "$ref": "#/channels/polymarket_order_book/messages/orderBookUpdateEvent" + } + ] + } + }, + "components": { + "messages": { + "TradesStreamSubscribe": { + "summary": "Subscribe to trades stream", + "payload": { + "$ref": "#/components/schemas/TradesStreamSubscribeMessage" + } + }, + "TradeStreamEvent": { + "summary": "a matched trade on a subscribed market/position/event/slug", + "payload": { + "$ref": "#/components/schemas/TradeStreamEvent" + } + }, + "AssetPricesSubscribe": { + "summary": "Subscribe to asset prices stream", + "payload": { + "$ref": "#/components/schemas/AssetPricesSubscribeMessage" + } + }, + "AssetPriceTickEvent": { + "summary": "a crypto-asset price tick", + "payload": { + "$ref": "#/components/schemas/AssetPriceTickEvent" + } + }, + "AssetPriceWindowUpdateEvent": { + "summary": "candle open or close for a crypto asset", + "payload": { + "$ref": "#/components/schemas/AssetPriceWindowUpdateEvent" + } + }, + "AssetWindowUpdatesSubscribe": { + "summary": "Subscribe to asset window updates stream", + "payload": { + "$ref": "#/components/schemas/AssetWindowUpdatesSubscribeMessage" + } + }, + "AssetWindowUpdateEvent": { + "summary": "Server-pushed event from the polymarket_asset_window_updates room", + "payload": { + "$ref": "#/components/schemas/AssetWindowUpdateEvent" + } + }, + "MarketMetricsSubscribe": { + "summary": "Subscribe to market (condition) metrics stream", + "payload": { + "$ref": "#/components/schemas/MarketMetricsSubscribeMessage" + } + }, + "MarketMetricsEvent": { + "summary": "updated metrics for a condition", + "payload": { + "$ref": "#/components/schemas/MarketMetricsEvent" + } + }, + "EventMetricsSubscribe": { + "summary": "Subscribe to event metrics stream", + "payload": { + "$ref": "#/components/schemas/EventMetricsSubscribeMessage" + } + }, + "EventMetricsEvent": { + "summary": "updated aggregated metrics for an event", + "payload": { + "$ref": "#/components/schemas/EventMetricsEvent" + } + }, + "PositionMetricsSubscribe": { + "summary": "Subscribe to position (outcome token) metrics stream", + "payload": { + "$ref": "#/components/schemas/PositionMetricsSubscribeMessage" + } + }, + "PositionMetricsEvent": { + "summary": "updated metrics for an outcome token", + "payload": { + "$ref": "#/components/schemas/PositionMetricsEvent" + } + }, + "TraderPnlSubscribe": { + "summary": "Subscribe to trader pnl stream", + "payload": { + "$ref": "#/components/schemas/TraderPnlSubscribeMessage" + } + }, + "TraderGlobalPnlEvent": { + "summary": "global (portfolio-level) PnL update for a trader", + "payload": { + "$ref": "#/components/schemas/TraderGlobalPnlEvent" + } + }, + "TraderMarketPnlEvent": { + "summary": "per-market PnL update for a trader", + "payload": { + "$ref": "#/components/schemas/TraderMarketPnlEvent" + } + }, + "TraderEventPnlEvent": { + "summary": "per-event PnL update for a trader", + "payload": { + "$ref": "#/components/schemas/TraderEventPnlEvent" + } + }, + "AccountsSubscribe": { + "summary": "Subscribe to account balances stream", + "payload": { + "$ref": "#/components/schemas/AccountsSubscribeMessage" + } + }, + "AccountsUpdateEvent": { + "summary": "ERC-1155 outcome token balance change for a wallet", + "payload": { + "$ref": "#/components/schemas/AccountsUpdateEvent" + } + }, + "UsdceUpdateEvent": { + "summary": "USDCe collateral balance change for a wallet", + "payload": { + "$ref": "#/components/schemas/UsdceUpdateEvent" + } + }, + "MaticUpdateEvent": { + "summary": "MATIC native balance change for a wallet", + "payload": { + "$ref": "#/components/schemas/MaticUpdateEvent" + } + }, + "OrderBookSubscribe": { + "summary": "Subscribe to order book snapshots stream", + "payload": { + "$ref": "#/components/schemas/OrderBookSubscribeMessage" + } + }, + "OrderBookUpdateEvent": { + "summary": "full CLOB orderbook snapshot for an outcome token", + "payload": { + "$ref": "#/components/schemas/OrderBookUpdateEvent" + } + } + }, + "schemas": { + "OrderBookUpdateEvent": { + "type": "object", + "description": "Server-pushed event: full CLOB orderbook snapshot for an outcome token. Envelope type: \"order_book_update\". Delivered whenever the book changes for a subscribed condition or position.", + "required": [ + "asset_id", + "market", + "bids", + "asks", + "timestamp", + "hash" + ], + "properties": { + "asset_id": { + "type": "string", + "description": "Hex token ID (position / outcome token)" + }, + "market": { + "type": "string", + "description": "Condition ID (hex)" + }, + "bids": { + "type": "array", + "items": { + "$ref": "#/components/schemas/OrderBookLevel" + }, + "description": "Bid levels sorted best-first (highest price first)" + }, + "asks": { + "type": "array", + "items": { + "$ref": "#/components/schemas/OrderBookLevel" + }, + "description": "Ask levels sorted best-first (lowest price first)" + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix milliseconds from CLOB message" + }, + "hash": { + "type": "string", + "description": "Orderbook content hash — identical hash means no change" + }, + "best_bid": { + "type": [ + "number", + "null" + ], + "description": "Best bid price (0–1)" + }, + "best_ask": { + "type": [ + "number", + "null" + ], + "description": "Best ask price (0–1)" + }, + "mid_price": { + "type": [ + "number", + "null" + ], + "description": "(best_bid + best_ask) / 2" + }, + "spread": { + "type": [ + "number", + "null" + ], + "description": "best_ask − best_bid" + }, + "bid_liquidity_usd": { + "type": [ + "number", + "null" + ], + "description": "Total USD value of all bid levels" + }, + "ask_liquidity_usd": { + "type": [ + "number", + "null" + ], + "description": "Total USD value of all ask levels" + }, + "bid_levels": { + "type": [ + "integer", + "null" + ], + "description": "Number of bid price levels" + }, + "ask_levels": { + "type": [ + "integer", + "null" + ], + "description": "Number of ask price levels" + } + } + }, + "OrderBookLevel": { + "type": "array", + "description": "A single price level: [price_string, size_string]", + "items": { + "type": "string" + }, + "minItems": 2, + "maxItems": 2 + }, + "OrderBookSubscribeResponse": { + "type": "object", + "description": "Server acknowledgement for an order book subscription", + "properties": { + "condition_ids": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Accepted condition IDs" + }, + "position_ids": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Accepted position IDs" + }, + "rejected": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Filter values that were rejected (invalid format or limit exceeded)" + } + } + }, + "OrderBookSubscribeMessage": { + "type": "object", + "description": "Subscribe to the order book stream. At least one filter is required. Maximum 500 combined condition_ids + position_ids per client.", + "required": [ + "action" + ], + "properties": { + "action": { + "type": "string", + "enum": [ + "subscribe", + "unsubscribe_all" + ] + }, + "condition_ids": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Condition IDs (markets). All positions within each market are delivered.", + "maxItems": 500 + }, + "position_ids": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Token / asset IDs (individual outcome positions, hex strings).", + "maxItems": 500 + } + } + }, + "MaticUpdateEvent": { + "type": "object", + "description": "Server-pushed event: MATIC native balance change for a wallet. Envelope type: \"matic_update\". Only delivered when `include_matic: true`.", + "required": [ + "address", + "block_number", + "updated_at" + ], + "properties": { + "address": { + "type": "string", + "description": "Wallet address" + }, + "balance": { + "type": "number", + "description": "Current MATIC balance — omitted when not available" + }, + "block_number": { + "type": "integer", + "format": "uint64" + }, + "updated_at": { + "type": "integer", + "format": "int64", + "description": "Unix seconds" + } + } + }, + "TradesStreamSubscribeMessage": { + "type": "object", + "description": "Subscribe to the trades stream. At least one filter field must be non-empty.", + "required": [ + "action" + ], + "properties": { + "action": { + "type": "string", + "enum": [ + "subscribe", + "unsubscribe_all" + ] + }, + "condition_ids": { + "type": "array", + "items": { + "type": "string" + }, + "description": "64-char hex condition IDs (with or without 0x prefix)" + }, + "market_slugs": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Market slugs" + }, + "event_slugs": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Event slugs — subscribes to all markets under each event" + }, + "position_ids": { + "type": "array", + "items": { + "type": "string" + }, + "description": "ERC-1155 outcome token IDs (decimal or hex strings)" + } + } + }, + "TradesStreamSubscribeResponse": { + "type": "object", + "description": "Server acknowledgement for a trades stream subscription", + "properties": { + "condition_ids": { + "type": "array", + "items": { + "type": "string" + } + }, + "market_slugs": { + "type": "array", + "items": { + "type": "string" + } + }, + "event_slugs": { + "type": "array", + "items": { + "type": "string" + } + }, + "position_ids": { + "type": "array", + "items": { + "type": "string" + } + }, + "rejected": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Filter values that were rejected (invalid format)" + } + } + }, + "AssetPricesSubscribeMessage": { + "type": "object", + "description": "Subscribe to the asset prices stream. Empty asset_symbols = all assets.", + "required": [ + "action" + ], + "properties": { + "action": { + "type": "string", + "enum": [ + "subscribe", + "unsubscribe_all" + ] + }, + "asset_symbols": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Uppercase asset symbols (e.g. \"BTC\", \"ETH\"). Empty = subscribe to all." + } + } + }, + "AssetPricesSubscribeResponse": { + "type": "object", + "description": "Server acknowledgement for an asset prices subscription", + "properties": { + "asset_symbols": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Accepted symbols. Empty array means subscribed to all symbols." + } + } + }, + "AssetWindowUpdatesSubscribeMessage": { + "type": "object", + "description": "Subscribe to the asset window updates stream. At least one of asset_symbols or timeframes must be non-empty.", + "required": [ + "action" + ], + "properties": { + "action": { + "type": "string", + "enum": [ + "subscribe", + "unsubscribe_all" + ] + }, + "asset_symbols": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Uppercase asset symbols (e.g. \"BTC\", \"ETH\")" + }, + "timeframes": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "5m", + "15m", + "1h", + "4h", + "1d", + "24h" + ] + }, + "description": "Candle sizes to filter by. \"1d\" and \"24h\" are treated as equivalent." + } + } + }, + "AssetWindowUpdatesSubscribeResponse": { + "type": "object", + "description": "Server acknowledgement for an asset window updates subscription", + "properties": { + "asset_symbols": { + "type": "array", + "items": { + "type": "string" + } + }, + "timeframes": { + "type": "array", + "items": { + "type": "string" + } + }, + "error": { + "type": [ + "string", + "null" + ], + "description": "Set if the subscription was rejected (e.g. no filters provided)" + } + } + }, + "MarketMetricsSubscribeMessage": { + "type": "object", + "description": "Subscribe to the market metrics stream. condition_ids is required and must be non-empty.", + "required": [ + "action", + "condition_ids" + ], + "properties": { + "action": { + "type": "string", + "enum": [ + "subscribe", + "unsubscribe_all" + ] + }, + "condition_ids": { + "type": "array", + "items": { + "type": "string" + }, + "description": "64-char hex condition IDs (with or without 0x prefix)", + "minItems": 1 + } + } + }, + "MarketMetricsSubscribeResponse": { + "type": "object", + "description": "Server acknowledgement for a market metrics subscription", + "properties": { + "condition_ids": { + "type": "array", + "items": { + "type": "string" + } + }, + "rejected": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Condition IDs that were rejected (invalid format)" + }, + "error": { + "type": [ + "string", + "null" + ], + "description": "Set if the entire subscription was rejected" + } + } + }, + "EventMetricsSubscribeMessage": { + "type": "object", + "description": "Subscribe to the event metrics stream. event_slugs is required and must be non-empty.", + "required": [ + "action", + "event_slugs" + ], + "properties": { + "action": { + "type": "string", + "enum": [ + "subscribe", + "unsubscribe_all" + ] + }, + "event_slugs": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Event slugs (lowercase)", + "minItems": 1 + } + } + }, + "EventMetricsSubscribeResponse": { + "type": "object", + "description": "Server acknowledgement for an event metrics subscription", + "properties": { + "event_slugs": { + "type": "array", + "items": { + "type": "string" + } + }, + "rejected": { + "type": "array", + "items": { + "type": "string" + } + }, + "error": { + "type": [ + "string", + "null" + ] + } + } + }, + "PositionMetricsSubscribeMessage": { + "type": "object", + "description": "Subscribe to the position metrics stream. position_ids is required and must be non-empty.", + "required": [ + "action", + "position_ids" + ], + "properties": { + "action": { + "type": "string", + "enum": [ + "subscribe", + "unsubscribe_all" + ] + }, + "position_ids": { + "type": "array", + "items": { + "type": "string" + }, + "description": "ERC-1155 outcome token IDs (decimal or hex strings)", + "minItems": 1 + } + } + }, + "PositionMetricsSubscribeResponse": { + "type": "object", + "description": "Server acknowledgement for a position metrics subscription", + "properties": { + "position_ids": { + "type": "array", + "items": { + "type": "string" + } + }, + "rejected": { + "type": "array", + "items": { + "type": "string" + } + }, + "error": { + "type": [ + "string", + "null" + ] + } + } + }, + "TraderPnlSubscribeMessage": { + "type": "object", + "description": "Subscribe to the trader PnL stream. traders is required and must be non-empty.", + "required": [ + "action", + "traders" + ], + "properties": { + "action": { + "type": "string", + "enum": [ + "subscribe", + "unsubscribe_all" + ] + }, + "traders": { + "type": "array", + "items": { + "type": "string" + }, + "description": "EVM wallet addresses", + "minItems": 1 + } + } + }, + "TraderPnlSubscribeResponse": { + "type": "object", + "description": "Server acknowledgement for a trader PnL subscription", + "properties": { + "traders": { + "type": "array", + "items": { + "type": "string" + } + }, + "rejected": { + "type": "array", + "items": { + "type": "string" + } + }, + "error": { + "type": [ + "string", + "null" + ] + } + } + }, + "TradeStreamEvent": { + "type": "object", + "description": "Server-pushed event: a matched trade on a subscribed market/position/event/slug. Envelope type: \"trade_stream_update\".", + "required": [ + "trader", + "taker", + "position_id", + "trade_id", + "hash", + "block", + "confirmed_at", + "amount_usd", + "shares_amount", + "fee", + "side", + "price" + ], + "properties": { + "trader": { + "type": "string", + "description": "Limit-order maker wallet" + }, + "taker": { + "type": "string", + "description": "Order taker wallet" + }, + "position_id": { + "type": "string", + "description": "ERC-1155 outcome token ID" + }, + "condition_id": { + "type": [ + "string", + "null" + ] + }, + "outcome": { + "type": [ + "string", + "null" + ], + "description": "Outcome name (e.g. \"Yes\")" + }, + "outcome_index": { + "type": [ + "integer", + "null" + ], + "description": "0 = Yes, 1 = No" + }, + "question": { + "type": [ + "string", + "null" + ] + }, + "market_slug": { + "type": [ + "string", + "null" + ] + }, + "event_slug": { + "type": [ + "string", + "null" + ] + }, + "trade_id": { + "type": "string" + }, + "hash": { + "type": "string", + "description": "Transaction hash" + }, + "block": { + "type": "integer", + "format": "int64" + }, + "confirmed_at": { + "type": "integer", + "format": "int64", + "description": "Unix seconds" + }, + "amount_usd": { + "type": "number" + }, + "shares_amount": { + "type": "number" + }, + "fee": { + "type": "number" + }, + "side": { + "type": "string", + "enum": [ + "Buy", + "Sell" + ] + }, + "price": { + "type": "number", + "minimum": 0.0, + "maximum": 1.0 + } + } + }, + "AssetPriceTickEvent": { + "type": "object", + "description": "Server-pushed event: a crypto-asset price tick. Envelope type: \"asset_price_tick\".", + "required": [ + "symbol", + "price", + "timestamp" + ], + "properties": { + "symbol": { + "type": "string", + "description": "Uppercase asset symbol (e.g. \"BTC\")" + }, + "price": { + "type": "number", + "description": "Current price in USD" + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix milliseconds" + }, + "change_24h": { + "type": [ + "number", + "null" + ], + "description": "24-hour price change %" + }, + "volume_24h": { + "type": [ + "number", + "null" + ], + "description": "24-hour trading volume USD" + }, + "market_cap": { + "type": [ + "number", + "null" + ] + } + } + }, + "AssetPriceWindowUpdateEvent": { + "type": "object", + "description": "Server-pushed event: candle open or close for a crypto asset. Envelope type: \"asset_price_window_update\".", + "required": [ + "symbol", + "timeframe", + "update_type", + "open", + "close", + "high", + "low", + "timestamp" + ], + "properties": { + "symbol": { + "type": "string", + "description": "Uppercase asset symbol" + }, + "timeframe": { + "type": "string", + "enum": [ + "5m", + "15m", + "1h", + "4h", + "1d", + "24h" + ] + }, + "update_type": { + "type": "string", + "enum": [ + "open", + "close" + ], + "description": "\"open\" = candle starting, \"close\" = candle finalised" + }, + "open": { + "type": "number" + }, + "close": { + "type": "number" + }, + "high": { + "type": "number" + }, + "low": { + "type": "number" + }, + "volume": { + "type": [ + "number", + "null" + ] + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Candle start time in Unix milliseconds" + } + } + }, + "AssetWindowUpdateEvent": { + "allOf": [ + { + "$ref": "#/components/schemas/AssetPriceWindowUpdateEvent" + } + ], + "description": "Server-pushed event from the polymarket_asset_window_updates room. Envelope type: \"asset_window_update\"." + }, + "MetricsTimeframe": { + "type": "object", + "description": "Volume and trade-count metrics for one timeframe window", + "required": [ + "timeframe", + "volume_usd", + "trade_count" + ], + "properties": { + "timeframe": { + "type": "string", + "enum": [ + "1m", + "5m", + "30m", + "1h", + "6h", + "24h", + "7d", + "30d" + ] + }, + "volume_usd": { + "type": "number", + "description": "USD volume in this window" + }, + "trade_count": { + "type": "integer", + "description": "Number of trades in this window" + } + } + }, + "MarketMetricsEvent": { + "type": "object", + "description": "Server-pushed event: updated metrics for a condition. Envelope type: \"market_metrics_update\".", + "required": [ + "condition_id", + "timeframes" + ], + "properties": { + "condition_id": { + "type": "string", + "description": "0x-prefixed 64-char hex condition ID" + }, + "market_slug": { + "type": [ + "string", + "null" + ] + }, + "timeframes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MetricsTimeframe" + } + } + } + }, + "EventMetricsEvent": { + "type": "object", + "description": "Server-pushed event: updated aggregated metrics for an event. Envelope type: \"event_metrics_update\".", + "required": [ + "event_slug", + "timeframes" + ], + "properties": { + "event_slug": { + "type": "string" + }, + "timeframes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MetricsTimeframe" + } + } + } + }, + "PositionMetricsEvent": { + "type": "object", + "description": "Server-pushed event: updated metrics for an outcome token. Envelope type: \"position_metrics_update\".", + "required": [ + "position_id", + "timeframes" + ], + "properties": { + "position_id": { + "type": "string", + "description": "ERC-1155 token ID (decimal string)" + }, + "condition_id": { + "type": [ + "string", + "null" + ] + }, + "outcome": { + "type": [ + "string", + "null" + ] + }, + "timeframes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MetricsTimeframe" + } + } + } + }, + "PnlTimeframes": { + "type": "object", + "description": "PnL figures broken down by timeframe", + "properties": { + "1d": { + "type": [ + "number", + "null" + ], + "description": "1-day PnL in USD" + }, + "7d": { + "type": [ + "number", + "null" + ] + }, + "30d": { + "type": [ + "number", + "null" + ] + }, + "all": { + "type": [ + "number", + "null" + ], + "description": "All-time PnL in USD" + } + } + }, + "TraderGlobalPnlEvent": { + "type": "object", + "description": "Server-pushed event: global (portfolio-level) PnL update for a trader. Envelope type: \"trader_global_pnl_update\".", + "required": [ + "trader", + "realized_pnl", + "unrealized_pnl", + "timeframe" + ], + "properties": { + "trader": { + "type": "string", + "description": "Trader EVM address" + }, + "realized_pnl": { + "type": "number", + "description": "Realized PnL in USD" + }, + "unrealized_pnl": { + "type": "number", + "description": "Unrealized PnL in USD" + }, + "total_pnl": { + "type": [ + "number", + "null" + ] + }, + "timeframe": { + "type": "string", + "description": "Window that triggered the update" + }, + "updated_at": { + "type": "integer", + "format": "int64", + "description": "Unix seconds" + } + } + }, + "TraderMarketPnlEvent": { + "type": "object", + "description": "Server-pushed event: per-market PnL update for a trader. Envelope type: \"trader_market_pnl_update\".", + "required": [ + "trader", + "condition_id", + "realized_pnl", + "unrealized_pnl", + "timeframe" + ], + "properties": { + "trader": { + "type": "string" + }, + "condition_id": { + "type": "string" + }, + "market_slug": { + "type": [ + "string", + "null" + ] + }, + "realized_pnl": { + "type": "number" + }, + "unrealized_pnl": { + "type": "number" + }, + "total_pnl": { + "type": [ + "number", + "null" + ] + }, + "timeframe": { + "type": "string" + }, + "updated_at": { + "type": "integer", + "format": "int64" + } + } + }, + "TraderEventPnlEvent": { + "type": "object", + "description": "Server-pushed event: per-event PnL update for a trader. Envelope type: \"trader_event_pnl_update\".", + "required": [ + "trader", + "event_slug", + "realized_pnl", + "unrealized_pnl", + "timeframe" + ], + "properties": { + "trader": { + "type": "string" + }, + "event_slug": { + "type": "string" + }, + "realized_pnl": { + "type": "number" + }, + "unrealized_pnl": { + "type": "number" + }, + "total_pnl": { + "type": [ + "number", + "null" + ] + }, + "timeframe": { + "type": "string" + }, + "updated_at": { + "type": "integer", + "format": "int64" + } + } + }, + "AccountsSubscribeMessage": { + "type": "object", + "description": "Subscribe to the accounts stream. `wallets` is required. Share balance updates (`accounts_update`) are always delivered. Set `include_usdce` or `include_matic` to also receive those balance streams.", + "required": [ + "action", + "wallets" + ], + "properties": { + "action": { + "type": "string", + "enum": [ + "subscribe", + "unsubscribe_all" + ] + }, + "wallets": { + "type": "array", + "items": { + "type": "string" + }, + "description": "EVM wallet addresses", + "minItems": 1 + }, + "include_usdce": { + "type": "boolean", + "default": false, + "description": "Also stream USDCe collateral balance updates for subscribed wallets" + }, + "include_matic": { + "type": "boolean", + "default": false, + "description": "Also stream MATIC gas balance updates for subscribed wallets" + } + } + }, + "AccountsSubscribeResponse": { + "type": "object", + "description": "Server acknowledgement for an accounts subscription", + "properties": { + "wallets": { + "type": "array", + "items": { + "type": "string" + } + }, + "rejected": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Addresses rejected (invalid format)" + }, + "include_usdce": { + "type": "boolean" + }, + "include_matic": { + "type": "boolean" + }, + "error": { + "type": [ + "string", + "null" + ] + } + } + }, + "AccountsUpdateEvent": { + "type": "object", + "description": "Server-pushed event: ERC-1155 outcome token balance change for a wallet. Envelope type: \"accounts_update\".", + "required": [ + "wallet", + "position_id", + "balance", + "block_number", + "updated_at" + ], + "properties": { + "wallet": { + "type": "string", + "description": "Wallet address" + }, + "position_id": { + "type": "string", + "description": "ERC-1155 outcome token ID (decimal string)" + }, + "balance": { + "type": "string", + "description": "Current token balance (U256 as decimal string)" + }, + "block_number": { + "type": "integer", + "format": "int64" + }, + "updated_at": { + "type": "integer", + "format": "int64", + "description": "Unix seconds" + }, + "condition_id": { + "type": "string", + "description": "Condition ID — omitted when not available" + }, + "event_slug": { + "type": "string", + "description": "Event slug — omitted when not available" + } + } + }, + "UsdceUpdateEvent": { + "type": "object", + "description": "Server-pushed event: USDCe collateral balance change for a wallet. Envelope type: \"usdce_update\". Only delivered when `include_usdce: true`.", + "required": [ + "address", + "block_number", + "updated_at" + ], + "properties": { + "address": { + "type": "string", + "description": "Wallet address" + }, + "token_address": { + "type": "string", + "description": "USDCe contract address — omitted when not available" + }, + "balance": { + "type": "number", + "description": "Current USDCe balance — omitted when not available" + }, + "block_number": { + "type": "integer", + "format": "uint64" + }, + "updated_at": { + "type": "integer", + "format": "int64", + "description": "Unix seconds" + } + } + } + }, + "securitySchemes": { + "jwt": { + "type": "http", + "scheme": "bearer", + "bearerFormat": "JWT", + "description": "Send `{\"type\":\"authenticate\",\"jwt\":\"\"}` after connecting" + } + } + } +} \ No newline at end of file diff --git a/package.json b/package.json index 63a159b..86b5b55 100644 --- a/package.json +++ b/package.json @@ -24,14 +24,16 @@ "build": "rm -rf dist && bun build ./src/index.ts --target browser --format esm --sourcemap --outdir ./dist && bun build ./src/index.ts --target browser --format cjs --sourcemap --outdir ./dist-cjs && mv ./dist-cjs/index.js ./dist/index.cjs && mv ./dist-cjs/index.js.map ./dist/index.cjs.map && rm -rf dist-cjs && tsc --emitDeclarationOnly", "check-routes": "bun run scripts/check-routes.ts", "fix-spec": "bun run scripts/fix-spec.ts", - "prep": "bun run fetch-spec:polymarket && bun run fix-spec && bun run generate:polymarket && bun run fetch-spec:webhooks && bun run generate:webhooks && bun run check-routes && bun run build", + "prep": "bun run fetch-spec:polymarket && bun run fix-spec && bun run generate:polymarket && bun run fetch-spec:webhooks && bun run generate:webhooks && bun run fetch-spec:ws && bun run generate:ws && bun run check-routes && bun run build", "test": "bun test", "test:watch": "bun test --watch", "typecheck": "bun run tsc -p tsconfig.check.json", "fetch-spec:polymarket": "curl -s -o openapi/polymarket.json https://api.struct.to/api-docs/openapi.json", "generate:polymarket": "openapi-typescript openapi/polymarket.json -o src/generated/polymarket.ts", "fetch-spec:webhooks": "curl -s -o openapi/webhooks.json https://api.struct.to/webhookopenapi.json", - "generate:webhooks": "openapi-typescript openapi/webhooks.json -o src/generated/webhooks.ts" + "generate:webhooks": "openapi-typescript openapi/webhooks.json -o src/generated/webhooks.ts", + "fetch-spec:ws": "curl -s -o openapi/ws.json https://api.struct.to/asyncapi.json", + "generate:ws": "bun run scripts/generate-ws-types.ts" }, "devDependencies": { "@types/bun": "latest", diff --git a/scripts/check-routes.ts b/scripts/check-routes.ts index 6eebad4..b363470 100644 --- a/scripts/check-routes.ts +++ b/scripts/check-routes.ts @@ -3,6 +3,7 @@ import { join } from "node:path"; const NAMESPACES_DIR = join(import.meta.dirname, "../src/namespaces"); const TYPES_FILE = join(import.meta.dirname, "../src/types/index.ts"); +const WS_TYPES_FILE = join(import.meta.dirname, "../src/types/ws.ts"); interface SpecConfig { specPath: string; @@ -114,15 +115,37 @@ async function getExportedSchemas(typesContent: string): Promise> { const exported = new Set(); for (const m of typesContent.matchAll(/Schemas\["(\w+)"\]/g)) exported.add(m[1]); for (const m of typesContent.matchAll(/WebhookSchemas\["(\w+)"\]/g)) exported.add(m[1]); + for (const m of typesContent.matchAll(/WsSchemas\["(\w+)"\]/g)) exported.add(m[1]); for (const m of typesContent.matchAll(/export type (\w+)\s*=/g)) exported.add(m[1]); for (const m of typesContent.matchAll(/export interface (\w+)/g)) exported.add(m[1]); return exported; } +async function getWsSpecRooms(jsonSpecPath: string): Promise { + const spec = JSON.parse(await readFile(jsonSpecPath, "utf-8")); + return Object.keys(spec.channels ?? {}); +} + +async function getSdkWsRooms(): Promise> { + const content = await readFile(WS_TYPES_FILE, "utf-8"); + const rooms = new Set(); + const subscriptionMapMatch = content.match(/interface WsSubscriptionMap\s*\{([^}]+)\}/); + if (subscriptionMapMatch) { + const regex = /(\w+)\s*:/g; + let match: RegExpExecArray | null; + while ((match = regex.exec(subscriptionMapMatch[1])) !== null) { + rooms.add(match[1]); + } + } + return rooms; +} + let hasErrors = false; const typesContent = await readFile(TYPES_FILE, "utf-8"); -const exportedSchemas = await getExportedSchemas(typesContent); +const wsTypesContent = await readFile(join(import.meta.dirname, "../src/types/ws.ts"), "utf-8"); +const combinedTypesContent = typesContent + "\n" + wsTypesContent; +const exportedSchemas = await getExportedSchemas(combinedTypesContent); for (const config of specs) { const specName = config.venuePrefix ?? "platform"; @@ -176,4 +199,47 @@ for (const config of specs) { } } +const wsJsonPath = join(import.meta.dirname, "../openapi/ws.json"); +const wsSpecRooms = await getWsSpecRooms(wsJsonPath); +const sdkWsRooms = await getSdkWsRooms(); + +const phantomWsRooms = [...sdkWsRooms].filter((r) => !wsSpecRooms.includes(r)); +const missingWsRooms = wsSpecRooms.filter((r) => !sdkWsRooms.has(r)); + +if (phantomWsRooms.length > 0) { + hasErrors = true; + console.error(`\x1b[31m✗ [ws] Phantom rooms (SDK rooms not in WS OpenAPI spec):\x1b[0m\n`); + for (const r of phantomWsRooms) { + console.error(` ${r}`); + } + console.error(); +} + +if (missingWsRooms.length > 0) { + hasErrors = true; + console.error(`\x1b[31m✗ [ws] Unimplemented rooms (WS OpenAPI spec rooms missing from SDK):\x1b[0m\n`); + for (const r of missingWsRooms) { + console.error(` ${r}`); + } + console.error(); +} + +if (phantomWsRooms.length === 0 && missingWsRooms.length === 0) { + console.log(`\x1b[32m✓ [ws] All SDK rooms match the WS OpenAPI spec.\x1b[0m`); +} + +const wsSpecSchemas = await getSpecSchemas(wsJsonPath); +const missingWsSchemas = wsSpecSchemas.filter((s) => !exportedSchemas.has(s)); + +if (missingWsSchemas.length > 0) { + hasErrors = true; + console.error(`\x1b[31m✗ [ws] Missing schema exports:\x1b[0m\n`); + for (const schema of missingWsSchemas) { + console.error(` WsSchemas["${schema}"]`); + } + console.error(); +} else { + console.log(`\x1b[32m✓ [ws] All WS schemas exported.\x1b[0m`); +} + process.exit(hasErrors ? 1 : 0); diff --git a/scripts/generate-ws-types.ts b/scripts/generate-ws-types.ts new file mode 100644 index 0000000..faddc34 --- /dev/null +++ b/scripts/generate-ws-types.ts @@ -0,0 +1,18 @@ +import openapiTS, { astToString } from "openapi-typescript"; +import { readFile, writeFile } from "node:fs/promises"; +import { join } from "node:path"; + +const asyncapiPath = join(import.meta.dirname, "../openapi/ws.json"); +const outputPath = join(import.meta.dirname, "../src/generated/ws.ts"); + +const asyncapi = JSON.parse(await readFile(asyncapiPath, "utf-8")); + +const ast = await openapiTS({ + openapi: "3.1.0", + info: asyncapi.info, + paths: {}, + components: { schemas: asyncapi.components.schemas }, +}); + +await writeFile(outputPath, astToString(ast)); +console.log("✓ Generated WS types from AsyncAPI spec"); diff --git a/src/generated/ws.ts b/src/generated/ws.ts new file mode 100644 index 0000000..0b01c37 --- /dev/null +++ b/src/generated/ws.ts @@ -0,0 +1,399 @@ +export type paths = Record; +export type webhooks = Record; +export interface components { + schemas: { + /** @description Server-pushed event: full CLOB orderbook snapshot for an outcome token. Envelope type: "order_book_update". Delivered whenever the book changes for a subscribed condition or position. */ + OrderBookUpdateEvent: { + /** @description Hex token ID (position / outcome token) */ + asset_id: string; + /** @description Condition ID (hex) */ + market: string; + /** @description Bid levels sorted best-first (highest price first) */ + bids: components["schemas"]["OrderBookLevel"][]; + /** @description Ask levels sorted best-first (lowest price first) */ + asks: components["schemas"]["OrderBookLevel"][]; + /** + * Format: int64 + * @description Unix milliseconds from CLOB message + */ + timestamp: number; + /** @description Orderbook content hash — identical hash means no change */ + hash: string; + /** @description Best bid price (0–1) */ + best_bid?: number | null; + /** @description Best ask price (0–1) */ + best_ask?: number | null; + /** @description (best_bid + best_ask) / 2 */ + mid_price?: number | null; + /** @description best_ask − best_bid */ + spread?: number | null; + /** @description Total USD value of all bid levels */ + bid_liquidity_usd?: number | null; + /** @description Total USD value of all ask levels */ + ask_liquidity_usd?: number | null; + /** @description Number of bid price levels */ + bid_levels?: number | null; + /** @description Number of ask price levels */ + ask_levels?: number | null; + }; + /** @description A single price level: [price_string, size_string] */ + OrderBookLevel: string[]; + /** @description Server acknowledgement for an order book subscription */ + OrderBookSubscribeResponse: { + /** @description Accepted condition IDs */ + condition_ids?: string[]; + /** @description Accepted position IDs */ + position_ids?: string[]; + /** @description Filter values that were rejected (invalid format or limit exceeded) */ + rejected?: string[]; + }; + /** @description Subscribe to the order book stream. At least one filter is required. Maximum 500 combined condition_ids + position_ids per client. */ + OrderBookSubscribeMessage: { + /** @enum {string} */ + action: "subscribe" | "unsubscribe_all"; + /** @description Condition IDs (markets). All positions within each market are delivered. */ + condition_ids?: string[]; + /** @description Token / asset IDs (individual outcome positions, hex strings). */ + position_ids?: string[]; + }; + /** @description Server-pushed event: MATIC native balance change for a wallet. Envelope type: "matic_update". Only delivered when `include_matic: true`. */ + MaticUpdateEvent: { + /** @description Wallet address */ + address: string; + /** @description Current MATIC balance — omitted when not available */ + balance?: number; + /** Format: uint64 */ + block_number: number; + /** + * Format: int64 + * @description Unix seconds + */ + updated_at: number; + }; + /** @description Subscribe to the trades stream. At least one filter field must be non-empty. */ + TradesStreamSubscribeMessage: { + /** @enum {string} */ + action: "subscribe" | "unsubscribe_all"; + /** @description 64-char hex condition IDs (with or without 0x prefix) */ + condition_ids?: string[]; + /** @description Market slugs */ + market_slugs?: string[]; + /** @description Event slugs — subscribes to all markets under each event */ + event_slugs?: string[]; + /** @description ERC-1155 outcome token IDs (decimal or hex strings) */ + position_ids?: string[]; + }; + /** @description Server acknowledgement for a trades stream subscription */ + TradesStreamSubscribeResponse: { + condition_ids?: string[]; + market_slugs?: string[]; + event_slugs?: string[]; + position_ids?: string[]; + /** @description Filter values that were rejected (invalid format) */ + rejected?: string[]; + }; + /** @description Subscribe to the asset prices stream. Empty asset_symbols = all assets. */ + AssetPricesSubscribeMessage: { + /** @enum {string} */ + action: "subscribe" | "unsubscribe_all"; + /** @description Uppercase asset symbols (e.g. "BTC", "ETH"). Empty = subscribe to all. */ + asset_symbols?: string[]; + }; + /** @description Server acknowledgement for an asset prices subscription */ + AssetPricesSubscribeResponse: { + /** @description Accepted symbols. Empty array means subscribed to all symbols. */ + asset_symbols?: string[]; + }; + /** @description Subscribe to the asset window updates stream. At least one of asset_symbols or timeframes must be non-empty. */ + AssetWindowUpdatesSubscribeMessage: { + /** @enum {string} */ + action: "subscribe" | "unsubscribe_all"; + /** @description Uppercase asset symbols (e.g. "BTC", "ETH") */ + asset_symbols?: string[]; + /** @description Candle sizes to filter by. "1d" and "24h" are treated as equivalent. */ + timeframes?: ("5m" | "15m" | "1h" | "4h" | "1d" | "24h")[]; + }; + /** @description Server acknowledgement for an asset window updates subscription */ + AssetWindowUpdatesSubscribeResponse: { + asset_symbols?: string[]; + timeframes?: string[]; + /** @description Set if the subscription was rejected (e.g. no filters provided) */ + error?: string | null; + }; + /** @description Subscribe to the market metrics stream. condition_ids is required and must be non-empty. */ + MarketMetricsSubscribeMessage: { + /** @enum {string} */ + action: "subscribe" | "unsubscribe_all"; + /** @description 64-char hex condition IDs (with or without 0x prefix) */ + condition_ids: string[]; + }; + /** @description Server acknowledgement for a market metrics subscription */ + MarketMetricsSubscribeResponse: { + condition_ids?: string[]; + /** @description Condition IDs that were rejected (invalid format) */ + rejected?: string[]; + /** @description Set if the entire subscription was rejected */ + error?: string | null; + }; + /** @description Subscribe to the event metrics stream. event_slugs is required and must be non-empty. */ + EventMetricsSubscribeMessage: { + /** @enum {string} */ + action: "subscribe" | "unsubscribe_all"; + /** @description Event slugs (lowercase) */ + event_slugs: string[]; + }; + /** @description Server acknowledgement for an event metrics subscription */ + EventMetricsSubscribeResponse: { + event_slugs?: string[]; + rejected?: string[]; + error?: string | null; + }; + /** @description Subscribe to the position metrics stream. position_ids is required and must be non-empty. */ + PositionMetricsSubscribeMessage: { + /** @enum {string} */ + action: "subscribe" | "unsubscribe_all"; + /** @description ERC-1155 outcome token IDs (decimal or hex strings) */ + position_ids: string[]; + }; + /** @description Server acknowledgement for a position metrics subscription */ + PositionMetricsSubscribeResponse: { + position_ids?: string[]; + rejected?: string[]; + error?: string | null; + }; + /** @description Subscribe to the trader PnL stream. traders is required and must be non-empty. */ + TraderPnlSubscribeMessage: { + /** @enum {string} */ + action: "subscribe" | "unsubscribe_all"; + /** @description EVM wallet addresses */ + traders: string[]; + }; + /** @description Server acknowledgement for a trader PnL subscription */ + TraderPnlSubscribeResponse: { + traders?: string[]; + rejected?: string[]; + error?: string | null; + }; + /** @description Server-pushed event: a matched trade on a subscribed market/position/event/slug. Envelope type: "trade_stream_update". */ + TradeStreamEvent: { + /** @description Limit-order maker wallet */ + trader: string; + /** @description Order taker wallet */ + taker: string; + /** @description ERC-1155 outcome token ID */ + position_id: string; + condition_id?: string | null; + /** @description Outcome name (e.g. "Yes") */ + outcome?: string | null; + /** @description 0 = Yes, 1 = No */ + outcome_index?: number | null; + question?: string | null; + market_slug?: string | null; + event_slug?: string | null; + trade_id: string; + /** @description Transaction hash */ + hash: string; + /** Format: int64 */ + block: number; + /** + * Format: int64 + * @description Unix seconds + */ + confirmed_at: number; + amount_usd: number; + shares_amount: number; + fee: number; + /** @enum {string} */ + side: "Buy" | "Sell"; + price: number; + }; + /** @description Server-pushed event: a crypto-asset price tick. Envelope type: "asset_price_tick". */ + AssetPriceTickEvent: { + /** @description Uppercase asset symbol (e.g. "BTC") */ + symbol: string; + /** @description Current price in USD */ + price: number; + /** + * Format: int64 + * @description Unix milliseconds + */ + timestamp: number; + /** @description 24-hour price change % */ + change_24h?: number | null; + /** @description 24-hour trading volume USD */ + volume_24h?: number | null; + market_cap?: number | null; + }; + /** @description Server-pushed event: candle open or close for a crypto asset. Envelope type: "asset_price_window_update". */ + AssetPriceWindowUpdateEvent: { + /** @description Uppercase asset symbol */ + symbol: string; + /** @enum {string} */ + timeframe: "5m" | "15m" | "1h" | "4h" | "1d" | "24h"; + /** + * @description "open" = candle starting, "close" = candle finalised + * @enum {string} + */ + update_type: "open" | "close"; + open: number; + close: number; + high: number; + low: number; + volume?: number | null; + /** + * Format: int64 + * @description Candle start time in Unix milliseconds + */ + timestamp: number; + }; + /** @description Server-pushed event from the polymarket_asset_window_updates room. Envelope type: "asset_window_update". */ + AssetWindowUpdateEvent: components["schemas"]["AssetPriceWindowUpdateEvent"]; + /** @description Volume and trade-count metrics for one timeframe window */ + MetricsTimeframe: { + /** @enum {string} */ + timeframe: "1m" | "5m" | "30m" | "1h" | "6h" | "24h" | "7d" | "30d"; + /** @description USD volume in this window */ + volume_usd: number; + /** @description Number of trades in this window */ + trade_count: number; + }; + /** @description Server-pushed event: updated metrics for a condition. Envelope type: "market_metrics_update". */ + MarketMetricsEvent: { + /** @description 0x-prefixed 64-char hex condition ID */ + condition_id: string; + market_slug?: string | null; + timeframes: components["schemas"]["MetricsTimeframe"][]; + }; + /** @description Server-pushed event: updated aggregated metrics for an event. Envelope type: "event_metrics_update". */ + EventMetricsEvent: { + event_slug: string; + timeframes: components["schemas"]["MetricsTimeframe"][]; + }; + /** @description Server-pushed event: updated metrics for an outcome token. Envelope type: "position_metrics_update". */ + PositionMetricsEvent: { + /** @description ERC-1155 token ID (decimal string) */ + position_id: string; + condition_id?: string | null; + outcome?: string | null; + timeframes: components["schemas"]["MetricsTimeframe"][]; + }; + /** @description PnL figures broken down by timeframe */ + PnlTimeframes: { + /** @description 1-day PnL in USD */ + "1d"?: number | null; + "7d"?: number | null; + "30d"?: number | null; + /** @description All-time PnL in USD */ + all?: number | null; + }; + /** @description Server-pushed event: global (portfolio-level) PnL update for a trader. Envelope type: "trader_global_pnl_update". */ + TraderGlobalPnlEvent: { + /** @description Trader EVM address */ + trader: string; + /** @description Realized PnL in USD */ + realized_pnl: number; + /** @description Unrealized PnL in USD */ + unrealized_pnl: number; + total_pnl?: number | null; + /** @description Window that triggered the update */ + timeframe: string; + /** + * Format: int64 + * @description Unix seconds + */ + updated_at?: number; + }; + /** @description Server-pushed event: per-market PnL update for a trader. Envelope type: "trader_market_pnl_update". */ + TraderMarketPnlEvent: { + trader: string; + condition_id: string; + market_slug?: string | null; + realized_pnl: number; + unrealized_pnl: number; + total_pnl?: number | null; + timeframe: string; + /** Format: int64 */ + updated_at?: number; + }; + /** @description Server-pushed event: per-event PnL update for a trader. Envelope type: "trader_event_pnl_update". */ + TraderEventPnlEvent: { + trader: string; + event_slug: string; + realized_pnl: number; + unrealized_pnl: number; + total_pnl?: number | null; + timeframe: string; + /** Format: int64 */ + updated_at?: number; + }; + /** @description Subscribe to the accounts stream. `wallets` is required. Share balance updates (`accounts_update`) are always delivered. Set `include_usdce` or `include_matic` to also receive those balance streams. */ + AccountsSubscribeMessage: { + /** @enum {string} */ + action: "subscribe" | "unsubscribe_all"; + /** @description EVM wallet addresses */ + wallets: string[]; + /** + * @description Also stream USDCe collateral balance updates for subscribed wallets + * @default false + */ + include_usdce: boolean; + /** + * @description Also stream MATIC gas balance updates for subscribed wallets + * @default false + */ + include_matic: boolean; + }; + /** @description Server acknowledgement for an accounts subscription */ + AccountsSubscribeResponse: { + wallets?: string[]; + /** @description Addresses rejected (invalid format) */ + rejected?: string[]; + include_usdce?: boolean; + include_matic?: boolean; + error?: string | null; + }; + /** @description Server-pushed event: ERC-1155 outcome token balance change for a wallet. Envelope type: "accounts_update". */ + AccountsUpdateEvent: { + /** @description Wallet address */ + wallet: string; + /** @description ERC-1155 outcome token ID (decimal string) */ + position_id: string; + /** @description Current token balance (U256 as decimal string) */ + balance: string; + /** Format: int64 */ + block_number: number; + /** + * Format: int64 + * @description Unix seconds + */ + updated_at: number; + /** @description Condition ID — omitted when not available */ + condition_id?: string; + /** @description Event slug — omitted when not available */ + event_slug?: string; + }; + /** @description Server-pushed event: USDCe collateral balance change for a wallet. Envelope type: "usdce_update". Only delivered when `include_usdce: true`. */ + UsdceUpdateEvent: { + /** @description Wallet address */ + address: string; + /** @description USDCe contract address — omitted when not available */ + token_address?: string; + /** @description Current USDCe balance — omitted when not available */ + balance?: number; + /** Format: uint64 */ + block_number: number; + /** + * Format: int64 + * @description Unix seconds + */ + updated_at: number; + }; + }; + responses: never; + parameters: never; + requestBodies: never; + headers: never; + pathItems: never; +} +export type $defs = Record; +export type operations = Record; diff --git a/src/types/index.ts b/src/types/index.ts index 4f5f08b..37592f6 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -12,6 +12,10 @@ export type { operations as WebhookOperations, paths as WebhookPaths, } from "../generated/webhooks.js"; +export type { WsSchemas } from "./ws-helpers.js"; +export type { + components as WsComponents, +} from "../generated/ws.js"; import type { Schemas, OperationQuery } from "./helpers.js"; import type { WebhookSchemas, WebhookOperationQuery, WebhookOperationRequestBody } from "./webhook-helpers.js"; @@ -397,11 +401,45 @@ export type { Address, PaginationParams, SortParams, Venue } from "./common.js"; export type { ConnectionState, StructWebSocketConfig, - PredictionTrade, - EnrichedPredictionTrade, - PredictionMarketMetadata, - PredictionWalletTrackingAlert, + WsRoomId, + WsFiltersOptionalRoom, + WsFiltersRequiredRoom, WebSocketEventMap, - WebSocketMessage, - WebSocketServerMessage, + WsSubscriptionMap, + WsSubscribeResponseMap, + TradesSubscribeFilters, + AssetPricesSubscribeFilters, + AssetWindowUpdatesSubscribeFilters, + MarketMetricsSubscribeFilters, + EventMetricsSubscribeFilters, + PositionMetricsSubscribeFilters, + TraderPnlSubscribeFilters, + AccountsSubscribeFilters, + OrderBookSubscribeFilters, + TradeStreamEvent, + AssetPriceTickEvent, + AssetPriceWindowUpdateEvent, + AssetWindowUpdateEvent, + WsMetricsTimeframe, + MarketMetricsEvent, + EventMetricsEvent, + PositionMetricsEvent, + WsPnlTimeframes, + TraderGlobalPnlEvent, + TraderMarketPnlEvent, + TraderEventPnlEvent, + AccountsUpdateEvent, + UsdceUpdateEvent, + MaticUpdateEvent, + WsOrderBookLevel, + OrderBookUpdateEvent, + TradesStreamSubscribeResponse, + AssetPricesSubscribeResponse, + AssetWindowUpdatesSubscribeResponse, + MarketMetricsSubscribeResponse, + EventMetricsSubscribeResponse, + PositionMetricsSubscribeResponse, + TraderPnlSubscribeResponse, + AccountsSubscribeResponse, + OrderBookSubscribeResponse, } from "./ws.js"; diff --git a/src/types/ws-helpers.ts b/src/types/ws-helpers.ts new file mode 100644 index 0000000..a72eea8 --- /dev/null +++ b/src/types/ws-helpers.ts @@ -0,0 +1,3 @@ +import type { components } from "../generated/ws.js"; + +export type WsSchemas = components["schemas"]; diff --git a/src/types/ws.ts b/src/types/ws.ts index 7652a15..d8602b4 100644 --- a/src/types/ws.ts +++ b/src/types/ws.ts @@ -1,114 +1,109 @@ -import type { Address } from "./common.js"; import type { RetryConfig } from "./http.js"; +import type { WsSchemas } from "./ws-helpers.js"; export type ConnectionState = "disconnected" | "connecting" | "connected" | "reconnecting"; export interface StructWebSocketConfig { apiKey: string; - baseUrl?: string; + wsUrl?: string; reconnect?: RetryConfig; + subscribeTimeout?: number; } -export interface PredictionTrade { - id: string; - hash: string; - chain_id: number; - block: number; - confirmed_at: number; - log_index: number; - block_index?: number; - order_hash?: string; - trader: Address; - taker: Address; - side: number; - condition_id: string | null; - position_id: string; - outcome: string | null; - outcome_index: number | null; - question: string | null; - slug: string | null; - event_slug?: string | null; - usd_amount: string; - shares_amount: string; - price: number; - probability: number | null; - fee?: string; - exchange?: number; - trade_type?: number; -} +export type WsRoomId = + | "polymarket_trades" + | "polymarket_asset_prices" + | "polymarket_asset_window_updates" + | "polymarket_market_metrics" + | "polymarket_event_metrics" + | "polymarket_position_metrics" + | "polymarket_trader_pnl" + | "polymarket_accounts" + | "polymarket_order_book"; -export interface EnrichedPredictionTrade { - id: string; - hash: string; - block: number; - confirmed_at: number; - trader: Address; - side: number; - position_id: string; - condition_id: string | null; - outcome: string | null; - outcome_index: number | null; - question: string; - slug: string; - event_slug: string; - image_url: string | null; - market_id: string | null; - title: string | null; - usd_amount: string; - shares_amount: string; - price: number; - probability: number | null; - smart_money_score: number; - insider_score: number; - categories: string[]; -} +export type WsFiltersOptionalRoom = "polymarket_asset_prices"; +export type WsFiltersRequiredRoom = Exclude; -export interface PredictionMarketMetadata { - slug: string | null; - question: string | null; - outcome: string | null; - outcome_index?: number | null; - image_url?: string | null; -} +export type TradesSubscribeFilters = Omit; +export type AssetPricesSubscribeFilters = Omit; +export type AssetWindowUpdatesSubscribeFilters = Omit; +export type MarketMetricsSubscribeFilters = Omit; +export type EventMetricsSubscribeFilters = Omit; +export type PositionMetricsSubscribeFilters = Omit; +export type TraderPnlSubscribeFilters = Omit; +export type AccountsSubscribeFilters = Pick & + Partial>; +export type OrderBookSubscribeFilters = Omit; -export interface PredictionWalletTrackingAlert { - is_buy: boolean; - trader: Address; - condition_id: string | null; - position_id: string; - usd_amount: string; - shares_amount: string; - price: number; - probability: number | null; - metadata: PredictionMarketMetadata | null; - confirmed_at: number; -} +export type TradeStreamEvent = WsSchemas["TradeStreamEvent"]; +export type AssetPriceTickEvent = WsSchemas["AssetPriceTickEvent"]; +export type AssetPriceWindowUpdateEvent = WsSchemas["AssetPriceWindowUpdateEvent"]; +export type AssetWindowUpdateEvent = WsSchemas["AssetWindowUpdateEvent"]; +export type WsMetricsTimeframe = WsSchemas["MetricsTimeframe"]; +export type MarketMetricsEvent = WsSchemas["MarketMetricsEvent"]; +export type EventMetricsEvent = WsSchemas["EventMetricsEvent"]; +export type PositionMetricsEvent = WsSchemas["PositionMetricsEvent"]; +export type WsPnlTimeframes = WsSchemas["PnlTimeframes"]; +export type TraderGlobalPnlEvent = WsSchemas["TraderGlobalPnlEvent"]; +export type TraderMarketPnlEvent = WsSchemas["TraderMarketPnlEvent"]; +export type TraderEventPnlEvent = WsSchemas["TraderEventPnlEvent"]; +export type AccountsUpdateEvent = WsSchemas["AccountsUpdateEvent"]; +export type UsdceUpdateEvent = WsSchemas["UsdceUpdateEvent"]; +export type MaticUpdateEvent = WsSchemas["MaticUpdateEvent"]; +export type WsOrderBookLevel = WsSchemas["OrderBookLevel"]; +export type OrderBookUpdateEvent = WsSchemas["OrderBookUpdateEvent"]; + +export type TradesStreamSubscribeResponse = WsSchemas["TradesStreamSubscribeResponse"]; +export type AssetPricesSubscribeResponse = WsSchemas["AssetPricesSubscribeResponse"]; +export type AssetWindowUpdatesSubscribeResponse = WsSchemas["AssetWindowUpdatesSubscribeResponse"]; +export type MarketMetricsSubscribeResponse = WsSchemas["MarketMetricsSubscribeResponse"]; +export type EventMetricsSubscribeResponse = WsSchemas["EventMetricsSubscribeResponse"]; +export type PositionMetricsSubscribeResponse = WsSchemas["PositionMetricsSubscribeResponse"]; +export type TraderPnlSubscribeResponse = WsSchemas["TraderPnlSubscribeResponse"]; +export type AccountsSubscribeResponse = WsSchemas["AccountsSubscribeResponse"]; +export type OrderBookSubscribeResponse = WsSchemas["OrderBookSubscribeResponse"]; export interface WebSocketEventMap { - market_trade: PredictionTrade; - whale_trade: EnrichedPredictionTrade; - smart_money_trade: EnrichedPredictionTrade; - insider_trade: EnrichedPredictionTrade; - wallet_tracking_alert: PredictionWalletTrackingAlert; - conditions_tracking_alert: PredictionTrade; + trade_stream_update: TradeStreamEvent; + asset_price_tick: AssetPriceTickEvent; + asset_price_window_update: AssetPriceWindowUpdateEvent; + asset_window_update: AssetWindowUpdateEvent; + market_metrics_update: MarketMetricsEvent; + event_metrics_update: EventMetricsEvent; + position_metrics_update: PositionMetricsEvent; + trader_global_pnl_update: TraderGlobalPnlEvent; + trader_market_pnl_update: TraderMarketPnlEvent; + trader_event_pnl_update: TraderEventPnlEvent; + accounts_update: AccountsUpdateEvent; + usdce_update: UsdceUpdateEvent; + matic_update: MaticUpdateEvent; + order_book_update: OrderBookUpdateEvent; connected: void; disconnected: { code: number; reason: string }; reconnecting: { attempt: number }; error: Error; } -export interface WebSocketMessage { - type: string; - room_id?: string; - action?: string; - message?: Record; - wallet_addresses?: string[]; - condition_ids?: string[]; +export interface WsSubscriptionMap { + polymarket_trades: TradesSubscribeFilters; + polymarket_asset_prices: AssetPricesSubscribeFilters; + polymarket_asset_window_updates: AssetWindowUpdatesSubscribeFilters; + polymarket_market_metrics: MarketMetricsSubscribeFilters; + polymarket_event_metrics: EventMetricsSubscribeFilters; + polymarket_position_metrics: PositionMetricsSubscribeFilters; + polymarket_trader_pnl: TraderPnlSubscribeFilters; + polymarket_accounts: AccountsSubscribeFilters; + polymarket_order_book: OrderBookSubscribeFilters; } -export interface WebSocketServerMessage { - type: string; - data?: unknown; - room_id?: string; - message?: string; +export interface WsSubscribeResponseMap { + polymarket_trades: TradesStreamSubscribeResponse; + polymarket_asset_prices: AssetPricesSubscribeResponse; + polymarket_asset_window_updates: AssetWindowUpdatesSubscribeResponse; + polymarket_market_metrics: MarketMetricsSubscribeResponse; + polymarket_event_metrics: EventMetricsSubscribeResponse; + polymarket_position_metrics: PositionMetricsSubscribeResponse; + polymarket_trader_pnl: TraderPnlSubscribeResponse; + polymarket_accounts: AccountsSubscribeResponse; + polymarket_order_book: OrderBookSubscribeResponse; } diff --git a/src/ws-transport.ts b/src/ws-transport.ts index 82d8c59..8cb7761 100644 --- a/src/ws-transport.ts +++ b/src/ws-transport.ts @@ -1,5 +1,5 @@ import { WebSocketError, WebSocketClosedError } from "./errors.js"; -import type { ConnectionState, WebSocketMessage } from "./types/ws.js"; +import type { ConnectionState } from "./types/ws.js"; import type { RetryConfig } from "./types/http.js"; const DEFAULT_INITIAL_DELAY_MS = 1_000; @@ -19,8 +19,10 @@ export class WebSocketTransport { private reconnectTimer: ReturnType | null = null; private reconnectAttempt = 0; private intentionalClose = false; - private readonly pendingMessages: WebSocketMessage[] = []; - private readonly replayMessages: WebSocketMessage[] = []; + private connectResolve: (() => void) | null = null; + private connectReject: ((err: Error) => void) | null = null; + private readonly pendingMessages: Record[] = []; + private readonly replayMessages: Record[] = []; private readonly url: string; private readonly retry: RetryConfig; private readonly callbacks: WebSocketTransportCallbacks; @@ -35,17 +37,28 @@ export class WebSocketTransport { return this._state; } - connect(): void { - if (this._state === "connected" || this._state === "connecting" || this._state === "reconnecting") { - return; - } - if (this.ws && (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING)) { - return; + connect(): Promise { + if (this._state === "connected") return Promise.resolve(); + if (this._state === "connecting" || this._state === "reconnecting") { + return new Promise((resolve, reject) => { + const prevResolve = this.connectResolve; + const prevReject = this.connectReject; + this.connectResolve = () => { prevResolve?.(); resolve(); }; + this.connectReject = (err) => { prevReject?.(err); reject(err); }; + }); } + this.intentionalClose = false; this.clearReconnectTimer(); this.setState("connecting"); + + const promise = new Promise((resolve, reject) => { + this.connectResolve = resolve; + this.connectReject = reject; + }); + this.createSocket(); + return promise; } disconnect(): void { @@ -53,6 +66,7 @@ export class WebSocketTransport { this.clearReconnectTimer(); this.pendingMessages.length = 0; this.replayMessages.length = 0; + this.resolveConnect(new WebSocketClosedError(1000, "client disconnect")); if (this.ws) { this.ws.close(1000, "client disconnect"); this.ws = null; @@ -60,7 +74,7 @@ export class WebSocketTransport { this.setState("disconnected"); } - send(message: WebSocketMessage): void { + send(message: Record): void { if (this._state === "connected" && this.ws?.readyState === WebSocket.OPEN) { this.ws.send(JSON.stringify(message)); } else { @@ -68,29 +82,31 @@ export class WebSocketTransport { } } - addReplayMessage(message: WebSocketMessage): void { + addReplayMessage(message: Record): void { this.replayMessages.push(message); } - removeReplayMessages(predicate: (msg: WebSocketMessage) => boolean): void { - for (let i = this.replayMessages.length - 1; i >= 0; i--) { - if (predicate(this.replayMessages[i]!)) { - this.replayMessages.splice(i, 1); - } - } - } - clearReplayMessages(): void { this.replayMessages.length = 0; } + private resolveConnect(error?: Error): void { + if (error) { + this.connectReject?.(error); + } else { + this.connectResolve?.(); + } + this.connectResolve = null; + this.connectReject = null; + } + private createSocket(): void { try { this.ws = new WebSocket(this.url); } catch (err) { - this.callbacks.onError( - new WebSocketError("Failed to create WebSocket", { cause: err }), - ); + const error = new WebSocketError("Failed to create WebSocket", { cause: err }); + this.callbacks.onError(error); + this.resolveConnect(error); this.scheduleReconnect(); return; } @@ -100,6 +116,7 @@ export class WebSocketTransport { this.reconnectAttempt = 0; this.replaySubscriptions(); this.flushPendingMessages(); + this.resolveConnect(); this.callbacks.onOpen(); }; @@ -110,6 +127,7 @@ export class WebSocketTransport { this.callbacks.onClose(event.code, event.reason); return; } + this.resolveConnect(new WebSocketClosedError(event.code, event.reason)); this.callbacks.onClose(event.code, event.reason); this.scheduleReconnect(); }; diff --git a/src/ws.ts b/src/ws.ts index 746343e..e73aa4f 100644 --- a/src/ws.ts +++ b/src/ws.ts @@ -1,30 +1,40 @@ import { WebSocketTransport } from "./ws-transport.js"; +import { WebSocketError } from "./errors.js"; import type { ConnectionState, StructWebSocketConfig, WebSocketEventMap, - WebSocketMessage, - WebSocketServerMessage, + WsRoomId, + WsFiltersOptionalRoom, + WsFiltersRequiredRoom, + WsSubscriptionMap, + WsSubscribeResponseMap, } from "./types/ws.js"; -import type { Address } from "./types/common.js"; -const DEFAULT_BASE_URL = "https://api.struct.to/v1"; +const DEFAULT_WS_URL = "wss://api.struct.to/ws"; +const PING_INTERVAL_MS = 30_000; +const DEFAULT_SUBSCRIBE_TIMEOUT_MS = 10_000; type Listener = (payload: T) => void; +interface PendingSubscribe { + resolve: (data: unknown) => void; + reject: (err: Error) => void; + timer: ReturnType; +} + export class StructWebSocket { private readonly transport: WebSocketTransport; private readonly listeners = new Map>(); - private readonly activeMarkets = new Set(); - private readonly activeMarketPositions = new Set(); - private readonly activeWallets = new Set(); - private readonly activeConditions = new Set(); - private readonly activeSpecialRooms = new Set(); + private readonly subscriptions = new Map>(); + private readonly pendingSubscribes = new Map(); + private readonly subscribeTimeout: number; + private pingTimer: ReturnType | null = null; constructor(config: StructWebSocketConfig) { - const httpBase = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, ""); - const wsBase = httpBase.replace(/^https:\/\//, "wss://").replace(/^http:\/\//, "ws://"); - const url = `${wsBase}?token=${encodeURIComponent(config.apiKey)}`; + this.subscribeTimeout = config.subscribeTimeout ?? DEFAULT_SUBSCRIBE_TIMEOUT_MS; + const wsUrl = (config.wsUrl ?? DEFAULT_WS_URL).replace(/\/+$/, ""); + const url = `${wsUrl}?token=${encodeURIComponent(config.apiKey)}`; this.transport = new WebSocketTransport( url, @@ -43,35 +53,36 @@ export class StructWebSocket { return this.transport.state; } - connect(): void { - this.transport.connect(); + connect(): Promise { + return this.transport.connect(); } disconnect(): void { - this.activeMarkets.clear(); - this.activeMarketPositions.clear(); - this.activeWallets.clear(); - this.activeConditions.clear(); - this.activeSpecialRooms.clear(); + this.stopPing(); + for (const [, pending] of this.pendingSubscribes) { + clearTimeout(pending.timer); + pending.reject(new WebSocketError("Disconnected")); + } + this.pendingSubscribes.clear(); + this.subscriptions.clear(); this.transport.disconnect(); } - on(event: K, listener: Listener): this { + on(event: K, listener: Listener): () => void { let set = this.listeners.get(event as string); if (!set) { set = new Set(); this.listeners.set(event as string, set); } set.add(listener); - return this; + return () => { set.delete(listener); }; } - off(event: K, listener: Listener): this { + off(event: K, listener: Listener): void { this.listeners.get(event as string)?.delete(listener); - return this; } - once(event: K, listener: Listener): this { + once(event: K, listener: Listener): () => void { const wrapper = (payload: WebSocketEventMap[K]) => { this.off(event, wrapper); listener(payload); @@ -79,142 +90,106 @@ export class StructWebSocket { return this.on(event, wrapper); } - subscribeMarket(conditionId: string): void { - if (this.activeMarkets.has(conditionId)) return; - this.activeMarkets.add(conditionId); - const msg = this.marketSubscribeMessage(conditionId); - this.transport.addReplayMessage(msg); - this.transport.send(msg); - } - - unsubscribeMarket(conditionId: string): void { - if (!this.activeMarkets.has(conditionId)) return; - this.activeMarkets.delete(conditionId); - const msg: WebSocketMessage = { - type: "unsubscribe_market", - room_id: `market_${conditionId}`, - message: {}, - }; - this.transport.removeReplayMessages( - (m) => m.type === "subscribe_market" && m.room_id === `market_${conditionId}`, - ); - this.transport.send(msg); - } - - subscribeMarketByPosition(positionId: string): void { - if (this.activeMarketPositions.has(positionId)) return; - this.activeMarketPositions.add(positionId); - const msg = this.marketPositionSubscribeMessage(positionId); - this.transport.addReplayMessage(msg); - this.transport.send(msg); - } - - unsubscribeMarketByPosition(positionId: string): void { - if (!this.activeMarketPositions.has(positionId)) return; - this.activeMarketPositions.delete(positionId); - const msg: WebSocketMessage = { - type: "unsubscribe_market", - room_id: `market_position_${positionId}`, - message: {}, - }; - this.transport.removeReplayMessages( - (m) => m.type === "subscribe_market" && m.room_id === `market_position_${positionId}`, - ); - this.transport.send(msg); - } - - trackWallets(addresses: Address[]): void { - const uniqueAddresses = [...new Set(addresses)]; - const added = uniqueAddresses.filter((addr) => !this.activeWallets.has(addr)); - if (added.length === 0) return; - for (const addr of added) this.activeWallets.add(addr); - const msg = this.walletTrackMessage("subscribe", added); - this.rebuildWalletReplay(); - this.transport.send(msg); - } - - untrackWallets(addresses: Address[]): void { - const uniqueAddresses = [...new Set(addresses)]; - const removed = uniqueAddresses.filter((addr) => this.activeWallets.has(addr)); - if (removed.length === 0) return; - for (const addr of removed) this.activeWallets.delete(addr); - const msg = this.walletTrackMessage("unsubscribe", removed); - this.rebuildWalletReplay(); - this.transport.send(msg); - } - - subscribeWhaleTrades(): void { - this.subscribeSpecialRoom("whale_trades"); + removeAllListeners(event?: keyof WebSocketEventMap): void { + if (event) { + this.listeners.delete(event as string); + } else { + this.listeners.clear(); + } } - unsubscribeWhaleTrades(): void { - this.unsubscribeSpecialRoom("whale_trades"); - } + subscribe(room: R, filters?: WsSubscriptionMap[R]): Promise; + subscribe(room: R, filters: WsSubscriptionMap[R]): Promise; + subscribe(room: R, filters?: WsSubscriptionMap[R]): Promise { + const resolvedFilters = (filters ?? {}) as Record; + const isNewRoom = !this.subscriptions.has(room); + this.subscriptions.set(room, resolvedFilters); + this.rebuildReplay(); - subscribeSmartMoneyTrades(): void { - this.subscribeSpecialRoom("smart_money_trades"); - } + if (isNewRoom) { + this.transport.send({ type: "join_room", payload: { room_id: room } }); + } + this.transport.send({ + type: "room_message", + payload: { room_id: room, message: { action: "subscribe", ...resolvedFilters } }, + }); + + const existing = this.pendingSubscribes.get(room); + if (existing) { + clearTimeout(existing.timer); + existing.reject(new WebSocketError("Superseded by new subscription")); + } - unsubscribeSmartMoneyTrades(): void { - this.unsubscribeSpecialRoom("smart_money_trades"); - } + return new Promise((resolve, reject) => { + const timer = setTimeout(() => { + this.pendingSubscribes.delete(room); + reject(new WebSocketError(`Subscribe to ${room} timed out`)); + }, this.subscribeTimeout); - subscribeInsiderTrades(): void { - this.subscribeSpecialRoom("insider_trades"); + this.pendingSubscribes.set(room, { + resolve: resolve as (data: unknown) => void, + reject, + timer, + }); + }); } - unsubscribeInsiderTrades(): void { - this.unsubscribeSpecialRoom("insider_trades"); - } + unsubscribe(room: WsRoomId): void { + if (!this.subscriptions.has(room)) return; - trackConditions(conditionIds: string[]): void { - const uniqueConditionIds = [...new Set(conditionIds)]; - const added = uniqueConditionIds.filter((id) => !this.activeConditions.has(id)); - if (added.length === 0) return; - for (const id of added) this.activeConditions.add(id); - const msg = this.conditionsTrackMessage("subscribe", added); - this.rebuildConditionsReplay(); - this.transport.send(msg); - } + const pending = this.pendingSubscribes.get(room); + if (pending) { + clearTimeout(pending.timer); + pending.reject(new WebSocketError("Unsubscribed")); + this.pendingSubscribes.delete(room); + } - untrackConditions(conditionIds: string[]): void { - const uniqueConditionIds = [...new Set(conditionIds)]; - const removed = uniqueConditionIds.filter((id) => this.activeConditions.has(id)); - if (removed.length === 0) return; - for (const id of removed) this.activeConditions.delete(id); - const msg = this.conditionsTrackMessage("unsubscribe", removed); - this.rebuildConditionsReplay(); - this.transport.send(msg); + this.transport.send({ + type: "room_message", + payload: { room_id: room, message: { action: "unsubscribe_all" } }, + }); + this.transport.send({ type: "leave_room", payload: { room_id: room } }); + this.subscriptions.delete(room); + this.rebuildReplay(); + } + + private rebuildReplay(): void { + this.transport.clearReplayMessages(); + for (const [roomId, filters] of this.subscriptions) { + this.transport.addReplayMessage({ type: "join_room", payload: { room_id: roomId } }); + this.transport.addReplayMessage({ + type: "room_message", + payload: { room_id: roomId, message: { action: "subscribe", ...filters } }, + }); + } } private handleOpen(): void { + this.startPing(); this.emit("connected", undefined as never); } private handleClose(code: number, reason: string): void { + this.stopPing(); this.emit("disconnected", { code, reason }); } private handleMessage(raw: unknown): void { - const msg = raw as WebSocketServerMessage; - if (!msg || typeof msg !== "object") return; - - const roomId = msg.room_id ?? ""; - const type = msg.type; - - if (type === "market_trade" || roomId.startsWith("market_")) { - this.emit("market_trade", msg.data as never); - } else if (type === "whale_trade" || roomId === "whale_trades") { - this.emit("whale_trade", msg.data as never); - } else if (type === "smart_money_trade" || roomId === "smart_money_trades") { - this.emit("smart_money_trade", msg.data as never); - } else if (type === "insider_trade" || roomId === "insider_trades") { - this.emit("insider_trade", msg.data as never); - } else if (type === "wallet_tracking_alert") { - this.emit("wallet_tracking_alert", msg.data as never); - } else if (type === "conditions_tracking_alert") { - this.emit("conditions_tracking_alert", msg.data as never); + const msg = raw as { type?: string; room_id?: string; data?: unknown }; + if (!msg || typeof msg !== "object" || !msg.type) return; + if (msg.type === "pong") return; + + if (msg.type === "subscribed" && msg.room_id) { + const pending = this.pendingSubscribes.get(msg.room_id as WsRoomId); + if (pending) { + clearTimeout(pending.timer); + this.pendingSubscribes.delete(msg.room_id as WsRoomId); + pending.resolve(msg.data); + } + return; } + + this.emit(msg.type as keyof WebSocketEventMap, msg.data as never); } private emit(event: K, payload: WebSocketEventMap[K]): void { @@ -227,55 +202,17 @@ export class StructWebSocket { } } - private marketSubscribeMessage(conditionId: string): WebSocketMessage { - return { type: "subscribe_market", room_id: `market_${conditionId}`, message: {} }; - } - - private marketPositionSubscribeMessage(positionId: string): WebSocketMessage { - return { type: "subscribe_market", room_id: `market_position_${positionId}`, message: {} }; - } - - private walletTrackMessage(action: string, addresses: Address[]): WebSocketMessage { - return { type: "wallet_tracking", action, wallet_addresses: addresses }; - } - - private conditionsTrackMessage(action: string, conditionIds: string[]): WebSocketMessage { - return { type: "conditions_tracking", action, condition_ids: conditionIds }; - } - - private subscribeSpecialRoom(roomId: string): void { - if (this.activeSpecialRooms.has(roomId)) return; - this.activeSpecialRooms.add(roomId); - const msg: WebSocketMessage = { type: "subscribe_market", room_id: roomId, message: {} }; - this.transport.addReplayMessage(msg); - this.transport.send(msg); - } - - private unsubscribeSpecialRoom(roomId: string): void { - if (!this.activeSpecialRooms.has(roomId)) return; - this.activeSpecialRooms.delete(roomId); - const msg: WebSocketMessage = { type: "unsubscribe_market", room_id: roomId, message: {} }; - this.transport.removeReplayMessages( - (m) => m.type === "subscribe_market" && m.room_id === roomId, - ); - this.transport.send(msg); - } - - private rebuildWalletReplay(): void { - this.transport.removeReplayMessages((m) => m.type === "wallet_tracking"); - if (this.activeWallets.size > 0) { - this.transport.addReplayMessage( - this.walletTrackMessage("subscribe", [...this.activeWallets]), - ); - } + private startPing(): void { + this.stopPing(); + this.pingTimer = setInterval(() => { + this.transport.send({ type: "ping" }); + }, PING_INTERVAL_MS); } - private rebuildConditionsReplay(): void { - this.transport.removeReplayMessages((m) => m.type === "conditions_tracking"); - if (this.activeConditions.size > 0) { - this.transport.addReplayMessage( - this.conditionsTrackMessage("subscribe", [...this.activeConditions]), - ); + private stopPing(): void { + if (this.pingTimer !== null) { + clearInterval(this.pingTimer); + this.pingTimer = null; } } } From c2b3c76d164eac64a96cd60e2f523427bc05e0f0 Mon Sep 17 00:00:00 2001 From: elliotdotsol Date: Wed, 18 Mar 2026 18:09:41 +0700 Subject: [PATCH 02/12] update: gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 6fd243c..3705285 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ dist/ *.tsbuildinfo .DS_Store .env -logs/ \ No newline at end of file +logs/ +*.tgz \ No newline at end of file From 3edb4b2adaf8cceb5dc2ee0710cd82076e9e3065 Mon Sep 17 00:00:00 2001 From: elliotdotsol Date: Wed, 18 Mar 2026 18:06:34 +0700 Subject: [PATCH 03/12] feat: rewrite WebSocket layer with AsyncAPI-driven room-based protocol MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the ad-hoc WS implementation with a typed, room-based protocol derived from the AsyncAPI spec. Types are auto-generated and rooms are validated by check-routes, matching the existing REST/webhook pattern. - Generic `subscribe(room, filters?)` / `unsubscribe(room)` with typed overloads (filters optional only for rooms where spec allows it) - `connect()` returns Promise, `subscribe()` returns Promise with server ack (rejected filters, timeout handling) - `on()` returns disposer function for ergonomic React/framework cleanup - `removeAllListeners()` for bulk teardown - Configurable `subscribeTimeout` via StructWebSocketConfig - Auto-ping keepalive (30s), replay subscriptions on reconnect - AsyncAPI spec pipeline: fetch → generate types → check rooms/schemas - 9 rooms: trades, asset_prices, asset_window_updates, market_metrics, event_metrics, position_metrics, trader_pnl, accounts, order_book Co-Authored-By: Claude Opus 4.6 (1M context) --- CLAUDE.md | 9 +- openapi/ws.json | 1742 ++++++++++++++++++++++++++++++++++ package.json | 6 +- scripts/check-routes.ts | 68 +- scripts/generate-ws-types.ts | 18 + src/generated/ws.ts | 399 ++++++++ src/types/index.ts | 50 +- src/types/ws-helpers.ts | 3 + src/types/ws.ts | 177 ++-- src/ws-transport.ts | 62 +- src/ws.ts | 309 +++--- 11 files changed, 2532 insertions(+), 311 deletions(-) create mode 100644 openapi/ws.json create mode 100644 scripts/generate-ws-types.ts create mode 100644 src/generated/ws.ts create mode 100644 src/types/ws-helpers.ts diff --git a/CLAUDE.md b/CLAUDE.md index bd4941c..851cbd3 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -17,6 +17,8 @@ TypeScript SDK (`@structbuild/sdk`) for prediction market APIs via `api.struct.t - **Check routes:** `bun run check-routes` (validates namespace routes match OpenAPI spec) - **Fetch webhook spec:** `bun run fetch-spec:webhooks` - **Generate webhook types:** `bun run generate:webhooks` +- **Fetch WS spec:** `bun run fetch-spec:ws` (AsyncAPI format) +- **Generate WS types:** `bun run generate:ws` - **Fix spec:** `bun run fix-spec` (fixes broken `$ref`s in the OpenAPI spec) - **Test:** `bun test` (integration tests against live API, requires `STRUCT_API_KEY`) - **Test watch:** `bun test --watch` @@ -29,11 +31,12 @@ TypeScript SDK (`@structbuild/sdk`) for prediction market APIs via `api.struct.t - `src/http.ts` — Generic `HttpClient` built on `fetch` with timeout via `AbortController`, query param building, exponential backoff retry (429/5xx), request/response hooks, and typed `HttpResponse` responses. - `src/errors.ts` — Error hierarchy: `StructError` → `HttpError` | `NetworkError` | `TimeoutError` | `WebSocketError` | `WebSocketClosedError`. - `src/paginate.ts` — `paginate()` async generator for offset-based pagination across any namespace method. -- `src/ws.ts` — `StructWebSocket` for real-time trade streaming. Event system (`on`/`off`/`once`), subscriptions (markets, positions, wallets, conditions, whale/smart-money/insider rooms), auto-replays subscriptions on reconnect. -- `src/ws-transport.ts` — Low-level WebSocket connection management with reconnection (exponential backoff + jitter), pending/replay message queues. -- `src/types/` — All type definitions. `common.ts` (pagination/sort/Venue), `helpers.ts` (OpenAPI type utilities: `OperationQuery`, `OperationPath`, `OperationResponse`), `webhook-helpers.ts` (webhook OpenAPI type utilities), `http.ts` (client config/request/response), `ws.ts` (WebSocket types). `index.ts` barrel exports all types. +- `src/ws.ts` — `StructWebSocket` for real-time streaming. Room-based protocol (`join_room`/`room_message`). Generic typed `subscribe(room, filters?)` / `unsubscribe(room)` with Promise-based acks. Event system (`on`/`off`/`once`/`removeAllListeners`), `on()` returns disposer function. Auto-replays subscriptions on reconnect, keepalive ping. +- `src/ws-transport.ts` — Low-level WebSocket connection management with reconnection (exponential backoff + jitter), pending/replay message queues. `connect()` returns `Promise`. +- `src/types/` — All type definitions. `common.ts` (pagination/sort/Venue), `helpers.ts` (OpenAPI type utilities: `OperationQuery`, `OperationPath`, `OperationResponse`), `webhook-helpers.ts` (webhook OpenAPI type utilities), `ws-helpers.ts` (WS type utilities: `WsSchemas`), `http.ts` (client config/request/response), `ws.ts` (WebSocket types: room IDs, subscribe filters, event types, event map, subscription/response maps). `index.ts` barrel exports all types. - `src/generated/polymarket.ts` — Auto-generated types from the Polymarket OpenAPI spec via `openapi-typescript`. Do not edit manually. - `src/generated/webhooks.ts` — Auto-generated types from the Webhooks OpenAPI spec. Do not edit manually. +- `src/generated/ws.ts` — Auto-generated types from the WS AsyncAPI spec (`scripts/generate-ws-types.ts`). Do not edit manually. - `src/index.ts` — Public barrel export. - `tests/integration.test.ts` — Auto-discovers namespace methods and runs them against the live API. Test config in `tests/integration.meta.ts` defines params and operationId mappings per method. diff --git a/openapi/ws.json b/openapi/ws.json new file mode 100644 index 0000000..34199ee --- /dev/null +++ b/openapi/ws.json @@ -0,0 +1,1742 @@ +{ + "asyncapi": "3.0.0", + "info": { + "title": "Polymarket WebSocket API", + "version": "1.0.0", + "description": "Real-time WebSocket streaming API for Polymarket prediction-market data.\n\n## Connection\nConnect to `wss://api.struct.to/ws` using a standard WebSocket client.\n\n## Authentication\nAfter connecting, send:\n```json\n{\"type\":\"authenticate\",\"jwt\":\"\"}\n```\nUnauthenticated connections can read public rooms but credit checks are enforced.\n\n## Joining a room\n```json\n{\"type\":\"join_room\",\"payload\":{\"room_id\":\"polymarket_trades\"}}\n```\n\n## Subscribing\nAfter joining, send a `room_message` with room-specific subscribe payload:\n```json\n{\n\"type\": \"room_message\",\n\"payload\": {\n\"room_id\": \"polymarket_trades\",\n\"message\": {\"action\":\"subscribe\",\"condition_ids\":[\"0xabc…\"]}\n}\n}\n```\n\n## Keepalive\nThe server expects a `{\"type\":\"ping\"}` or WebSocket ping frame at least every 60 seconds." + }, + "servers": { + "production": { + "host": "api.struct.to", + "pathname": "/ws", + "protocol": "wss", + "description": "Production WebSocket endpoint" + } + }, + "channels": { + "polymarket_trades": { + "address": "polymarket_trades", + "title": "Trades", + "summary": "Trades stream", + "description": "Real-time stream of matched Polymarket prediction-market trades. At least one filter is required — open-ended subscriptions are rejected to prevent fan-out across all trades.\n\n**Filters (at least one required):**\n- `condition_ids` — 64-char hex condition IDs (with or without `0x` prefix)\n- `market_slugs` — market slugs\n- `event_slugs` — event slugs (delivers all markets under each event)\n- `position_ids` — ERC-1155 token IDs (decimal or hex)\n\n**Unsubscribe:** Send `action: \"unsubscribe_all\"` to clear all subscriptions.", + "messages": { + "subscribe": { + "$ref": "#/components/messages/TradesStreamSubscribe" + }, + "tradeStreamEvent": { + "$ref": "#/components/messages/TradeStreamEvent" + } + } + }, + "polymarket_asset_prices": { + "address": "polymarket_asset_prices", + "title": "Asset Prices", + "summary": "Asset prices stream", + "description": "Real-time crypto-asset price feed (BTC, ETH, SOL, XRP, …). Delivers both raw `asset_price_tick` events on every price update and `asset_price_window_update` events at candle open/close boundaries.\n\n**Filter (optional):** `asset_symbols` — uppercase symbols to filter by. Empty array subscribes to all symbols.\n\n**Unsubscribe:** Send `action: \"unsubscribe_all\"`.", + "messages": { + "subscribe": { + "$ref": "#/components/messages/AssetPricesSubscribe" + }, + "assetPriceTickEvent": { + "$ref": "#/components/messages/AssetPriceTickEvent" + }, + "assetPriceWindowUpdateEvent": { + "$ref": "#/components/messages/AssetPriceWindowUpdateEvent" + } + } + }, + "polymarket_asset_window_updates": { + "address": "polymarket_asset_window_updates", + "title": "Asset Window Updates", + "summary": "Asset window updates stream", + "description": "Filtered stream of asset-price candle open/close events. Unlike `polymarket_asset_prices`, this room **requires** at least one filter so clients receive only the symbols and/or timeframes they care about.\n\n**Filters (at least one required):**\n- `asset_symbols` — uppercase symbols (e.g. `\"BTC\"`, `\"ETH\"`)\n- `timeframes` — candle sizes: `\"5m\"`, `\"15m\"`, `\"1h\"`, `\"4h\"`, `\"1d\"` / `\"24h\"`\n\n**Unsubscribe:** Send `action: \"unsubscribe_all\"`.", + "messages": { + "subscribe": { + "$ref": "#/components/messages/AssetWindowUpdatesSubscribe" + }, + "assetWindowUpdateEvent": { + "$ref": "#/components/messages/AssetWindowUpdateEvent" + } + } + }, + "polymarket_market_metrics": { + "address": "polymarket_market_metrics", + "title": "Market Metrics", + "summary": "Market (condition) metrics stream", + "description": "Real-time volume and transaction-count metrics per market condition, aggregated across multiple timeframes (`1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`).\n\n**Filter (required):** `condition_ids` — 64-char hex condition IDs. Invalid or malformed IDs are returned in `rejected`.\n\n**Unsubscribe:** Send `action: \"unsubscribe_all\"`.", + "messages": { + "subscribe": { + "$ref": "#/components/messages/MarketMetricsSubscribe" + }, + "marketMetricsEvent": { + "$ref": "#/components/messages/MarketMetricsEvent" + } + } + }, + "polymarket_event_metrics": { + "address": "polymarket_event_metrics", + "title": "Event Metrics", + "summary": "Event metrics stream", + "description": "Real-time volume and transaction-count metrics aggregated at the event (parent market group) level, across multiple timeframes.\n\n**Filter (required):** `event_slugs` — event slugs (lowercase).\n\n**Unsubscribe:** Send `action: \"unsubscribe_all\"`.", + "messages": { + "subscribe": { + "$ref": "#/components/messages/EventMetricsSubscribe" + }, + "eventMetricsEvent": { + "$ref": "#/components/messages/EventMetricsEvent" + } + } + }, + "polymarket_position_metrics": { + "address": "polymarket_position_metrics", + "title": "Position Metrics", + "summary": "Position (outcome token) metrics stream", + "description": "Real-time volume and transaction-count metrics per outcome-token position, across multiple timeframes.\n\n**Filter (required):** `position_ids` — ERC-1155 token IDs (decimal or hex; normalized to decimal strings internally).\n\n**Unsubscribe:** Send `action: \"unsubscribe_all\"`.", + "messages": { + "subscribe": { + "$ref": "#/components/messages/PositionMetricsSubscribe" + }, + "positionMetricsEvent": { + "$ref": "#/components/messages/PositionMetricsEvent" + } + } + }, + "polymarket_trader_pnl": { + "address": "polymarket_trader_pnl", + "title": "Trader PnL", + "summary": "Trader PnL stream", + "description": "Real-time profit-and-loss updates for tracked traders, delivered at global, market (condition), and event granularity.\n\n**Filter (required):** `traders` — EVM wallet addresses. Invalid addresses are returned in `rejected`.\n\n**Events pushed:** `trader_global_pnl_update`, `trader_market_pnl_update`, `trader_event_pnl_update`.\n\n**Unsubscribe:** Send `action: \"unsubscribe_all\"`.", + "messages": { + "subscribe": { + "$ref": "#/components/messages/TraderPnlSubscribe" + }, + "traderGlobalPnlEvent": { + "$ref": "#/components/messages/TraderGlobalPnlEvent" + }, + "traderMarketPnlEvent": { + "$ref": "#/components/messages/TraderMarketPnlEvent" + }, + "traderEventPnlEvent": { + "$ref": "#/components/messages/TraderEventPnlEvent" + } + } + }, + "polymarket_accounts": { + "address": "polymarket_accounts", + "title": "Accounts", + "summary": "Account balances stream", + "description": "Real-time balance updates for Polymarket wallet accounts.\n\nAlways streams ERC-1155 outcome token (shares) balance changes for subscribed wallets as `accounts_update` events. Opt in to additional token streams via boolean flags:\n- `include_usdce: true` — also receive `usdce_update` events (USDCe collateral balance)\n- `include_matic: true` — also receive `matic_update` events (MATIC gas balance)\n\n**Filter (required):** `wallets` — EVM wallet addresses. Invalid addresses are returned in `rejected`.\n\n**Unsubscribe:** Send `action: \"unsubscribe_all\"`.", + "messages": { + "subscribe": { + "$ref": "#/components/messages/AccountsSubscribe" + }, + "accountsUpdateEvent": { + "$ref": "#/components/messages/AccountsUpdateEvent" + }, + "usdceUpdateEvent": { + "$ref": "#/components/messages/UsdceUpdateEvent" + }, + "maticUpdateEvent": { + "$ref": "#/components/messages/MaticUpdateEvent" + } + } + }, + "polymarket_order_book": { + "address": "polymarket_order_book", + "title": "Order Book", + "summary": "Order book snapshots stream", + "description": "Real-time CLOB orderbook snapshots for Polymarket outcome tokens. Each event contains the full aggregated bid/ask book plus pre-computed derived metrics (best bid/ask, mid price, spread, USD liquidity depth, level counts).\n\n**Filters (at least one required, max 500 combined):**\n- `condition_ids` — 64-char hex condition IDs (market); delivers snapshots for all positions in that market\n- `position_ids` — hex token/asset IDs (individual outcome tokens)\n\n**Unsubscribe:** Send `action: \"unsubscribe_all\"`.", + "messages": { + "subscribe": { + "$ref": "#/components/messages/OrderBookSubscribe" + }, + "orderBookUpdateEvent": { + "$ref": "#/components/messages/OrderBookUpdateEvent" + } + } + } + }, + "operations": { + "subscribePolymarketTrades": { + "action": "send", + "channel": { + "$ref": "#/channels/polymarket_trades" + }, + "summary": "Subscribe to trades stream", + "messages": [ + { + "$ref": "#/channels/polymarket_trades/messages/subscribe" + } + ] + }, + "receivePolymarketTrades": { + "action": "receive", + "channel": { + "$ref": "#/channels/polymarket_trades" + }, + "summary": "Receive trades stream events", + "messages": [ + { + "$ref": "#/channels/polymarket_trades/messages/tradeStreamEvent" + } + ] + }, + "subscribePolymarketAssetPrices": { + "action": "send", + "channel": { + "$ref": "#/channels/polymarket_asset_prices" + }, + "summary": "Subscribe to asset prices stream", + "messages": [ + { + "$ref": "#/channels/polymarket_asset_prices/messages/subscribe" + } + ] + }, + "receivePolymarketAssetPrices": { + "action": "receive", + "channel": { + "$ref": "#/channels/polymarket_asset_prices" + }, + "summary": "Receive asset prices stream events", + "messages": [ + { + "$ref": "#/channels/polymarket_asset_prices/messages/assetPriceTickEvent" + }, + { + "$ref": "#/channels/polymarket_asset_prices/messages/assetPriceWindowUpdateEvent" + } + ] + }, + "subscribePolymarketAssetWindowUpdates": { + "action": "send", + "channel": { + "$ref": "#/channels/polymarket_asset_window_updates" + }, + "summary": "Subscribe to asset window updates stream", + "messages": [ + { + "$ref": "#/channels/polymarket_asset_window_updates/messages/subscribe" + } + ] + }, + "receivePolymarketAssetWindowUpdates": { + "action": "receive", + "channel": { + "$ref": "#/channels/polymarket_asset_window_updates" + }, + "summary": "Receive asset window updates stream events", + "messages": [ + { + "$ref": "#/channels/polymarket_asset_window_updates/messages/assetWindowUpdateEvent" + } + ] + }, + "subscribePolymarketMarketMetrics": { + "action": "send", + "channel": { + "$ref": "#/channels/polymarket_market_metrics" + }, + "summary": "Subscribe to market (condition) metrics stream", + "messages": [ + { + "$ref": "#/channels/polymarket_market_metrics/messages/subscribe" + } + ] + }, + "receivePolymarketMarketMetrics": { + "action": "receive", + "channel": { + "$ref": "#/channels/polymarket_market_metrics" + }, + "summary": "Receive market (condition) metrics stream events", + "messages": [ + { + "$ref": "#/channels/polymarket_market_metrics/messages/marketMetricsEvent" + } + ] + }, + "subscribePolymarketEventMetrics": { + "action": "send", + "channel": { + "$ref": "#/channels/polymarket_event_metrics" + }, + "summary": "Subscribe to event metrics stream", + "messages": [ + { + "$ref": "#/channels/polymarket_event_metrics/messages/subscribe" + } + ] + }, + "receivePolymarketEventMetrics": { + "action": "receive", + "channel": { + "$ref": "#/channels/polymarket_event_metrics" + }, + "summary": "Receive event metrics stream events", + "messages": [ + { + "$ref": "#/channels/polymarket_event_metrics/messages/eventMetricsEvent" + } + ] + }, + "subscribePolymarketPositionMetrics": { + "action": "send", + "channel": { + "$ref": "#/channels/polymarket_position_metrics" + }, + "summary": "Subscribe to position (outcome token) metrics stream", + "messages": [ + { + "$ref": "#/channels/polymarket_position_metrics/messages/subscribe" + } + ] + }, + "receivePolymarketPositionMetrics": { + "action": "receive", + "channel": { + "$ref": "#/channels/polymarket_position_metrics" + }, + "summary": "Receive position (outcome token) metrics stream events", + "messages": [ + { + "$ref": "#/channels/polymarket_position_metrics/messages/positionMetricsEvent" + } + ] + }, + "subscribePolymarketTraderPnl": { + "action": "send", + "channel": { + "$ref": "#/channels/polymarket_trader_pnl" + }, + "summary": "Subscribe to trader pnl stream", + "messages": [ + { + "$ref": "#/channels/polymarket_trader_pnl/messages/subscribe" + } + ] + }, + "receivePolymarketTraderPnl": { + "action": "receive", + "channel": { + "$ref": "#/channels/polymarket_trader_pnl" + }, + "summary": "Receive trader pnl stream events", + "messages": [ + { + "$ref": "#/channels/polymarket_trader_pnl/messages/traderGlobalPnlEvent" + }, + { + "$ref": "#/channels/polymarket_trader_pnl/messages/traderMarketPnlEvent" + }, + { + "$ref": "#/channels/polymarket_trader_pnl/messages/traderEventPnlEvent" + } + ] + }, + "subscribePolymarketAccounts": { + "action": "send", + "channel": { + "$ref": "#/channels/polymarket_accounts" + }, + "summary": "Subscribe to account balances stream", + "messages": [ + { + "$ref": "#/channels/polymarket_accounts/messages/subscribe" + } + ] + }, + "receivePolymarketAccounts": { + "action": "receive", + "channel": { + "$ref": "#/channels/polymarket_accounts" + }, + "summary": "Receive account balances stream events", + "messages": [ + { + "$ref": "#/channels/polymarket_accounts/messages/accountsUpdateEvent" + }, + { + "$ref": "#/channels/polymarket_accounts/messages/usdceUpdateEvent" + }, + { + "$ref": "#/channels/polymarket_accounts/messages/maticUpdateEvent" + } + ] + }, + "subscribePolymarketOrderBook": { + "action": "send", + "channel": { + "$ref": "#/channels/polymarket_order_book" + }, + "summary": "Subscribe to order book snapshots stream", + "messages": [ + { + "$ref": "#/channels/polymarket_order_book/messages/subscribe" + } + ] + }, + "receivePolymarketOrderBook": { + "action": "receive", + "channel": { + "$ref": "#/channels/polymarket_order_book" + }, + "summary": "Receive order book snapshots stream events", + "messages": [ + { + "$ref": "#/channels/polymarket_order_book/messages/orderBookUpdateEvent" + } + ] + } + }, + "components": { + "messages": { + "TradesStreamSubscribe": { + "summary": "Subscribe to trades stream", + "payload": { + "$ref": "#/components/schemas/TradesStreamSubscribeMessage" + } + }, + "TradeStreamEvent": { + "summary": "a matched trade on a subscribed market/position/event/slug", + "payload": { + "$ref": "#/components/schemas/TradeStreamEvent" + } + }, + "AssetPricesSubscribe": { + "summary": "Subscribe to asset prices stream", + "payload": { + "$ref": "#/components/schemas/AssetPricesSubscribeMessage" + } + }, + "AssetPriceTickEvent": { + "summary": "a crypto-asset price tick", + "payload": { + "$ref": "#/components/schemas/AssetPriceTickEvent" + } + }, + "AssetPriceWindowUpdateEvent": { + "summary": "candle open or close for a crypto asset", + "payload": { + "$ref": "#/components/schemas/AssetPriceWindowUpdateEvent" + } + }, + "AssetWindowUpdatesSubscribe": { + "summary": "Subscribe to asset window updates stream", + "payload": { + "$ref": "#/components/schemas/AssetWindowUpdatesSubscribeMessage" + } + }, + "AssetWindowUpdateEvent": { + "summary": "Server-pushed event from the polymarket_asset_window_updates room", + "payload": { + "$ref": "#/components/schemas/AssetWindowUpdateEvent" + } + }, + "MarketMetricsSubscribe": { + "summary": "Subscribe to market (condition) metrics stream", + "payload": { + "$ref": "#/components/schemas/MarketMetricsSubscribeMessage" + } + }, + "MarketMetricsEvent": { + "summary": "updated metrics for a condition", + "payload": { + "$ref": "#/components/schemas/MarketMetricsEvent" + } + }, + "EventMetricsSubscribe": { + "summary": "Subscribe to event metrics stream", + "payload": { + "$ref": "#/components/schemas/EventMetricsSubscribeMessage" + } + }, + "EventMetricsEvent": { + "summary": "updated aggregated metrics for an event", + "payload": { + "$ref": "#/components/schemas/EventMetricsEvent" + } + }, + "PositionMetricsSubscribe": { + "summary": "Subscribe to position (outcome token) metrics stream", + "payload": { + "$ref": "#/components/schemas/PositionMetricsSubscribeMessage" + } + }, + "PositionMetricsEvent": { + "summary": "updated metrics for an outcome token", + "payload": { + "$ref": "#/components/schemas/PositionMetricsEvent" + } + }, + "TraderPnlSubscribe": { + "summary": "Subscribe to trader pnl stream", + "payload": { + "$ref": "#/components/schemas/TraderPnlSubscribeMessage" + } + }, + "TraderGlobalPnlEvent": { + "summary": "global (portfolio-level) PnL update for a trader", + "payload": { + "$ref": "#/components/schemas/TraderGlobalPnlEvent" + } + }, + "TraderMarketPnlEvent": { + "summary": "per-market PnL update for a trader", + "payload": { + "$ref": "#/components/schemas/TraderMarketPnlEvent" + } + }, + "TraderEventPnlEvent": { + "summary": "per-event PnL update for a trader", + "payload": { + "$ref": "#/components/schemas/TraderEventPnlEvent" + } + }, + "AccountsSubscribe": { + "summary": "Subscribe to account balances stream", + "payload": { + "$ref": "#/components/schemas/AccountsSubscribeMessage" + } + }, + "AccountsUpdateEvent": { + "summary": "ERC-1155 outcome token balance change for a wallet", + "payload": { + "$ref": "#/components/schemas/AccountsUpdateEvent" + } + }, + "UsdceUpdateEvent": { + "summary": "USDCe collateral balance change for a wallet", + "payload": { + "$ref": "#/components/schemas/UsdceUpdateEvent" + } + }, + "MaticUpdateEvent": { + "summary": "MATIC native balance change for a wallet", + "payload": { + "$ref": "#/components/schemas/MaticUpdateEvent" + } + }, + "OrderBookSubscribe": { + "summary": "Subscribe to order book snapshots stream", + "payload": { + "$ref": "#/components/schemas/OrderBookSubscribeMessage" + } + }, + "OrderBookUpdateEvent": { + "summary": "full CLOB orderbook snapshot for an outcome token", + "payload": { + "$ref": "#/components/schemas/OrderBookUpdateEvent" + } + } + }, + "schemas": { + "OrderBookUpdateEvent": { + "type": "object", + "description": "Server-pushed event: full CLOB orderbook snapshot for an outcome token. Envelope type: \"order_book_update\". Delivered whenever the book changes for a subscribed condition or position.", + "required": [ + "asset_id", + "market", + "bids", + "asks", + "timestamp", + "hash" + ], + "properties": { + "asset_id": { + "type": "string", + "description": "Hex token ID (position / outcome token)" + }, + "market": { + "type": "string", + "description": "Condition ID (hex)" + }, + "bids": { + "type": "array", + "items": { + "$ref": "#/components/schemas/OrderBookLevel" + }, + "description": "Bid levels sorted best-first (highest price first)" + }, + "asks": { + "type": "array", + "items": { + "$ref": "#/components/schemas/OrderBookLevel" + }, + "description": "Ask levels sorted best-first (lowest price first)" + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix milliseconds from CLOB message" + }, + "hash": { + "type": "string", + "description": "Orderbook content hash — identical hash means no change" + }, + "best_bid": { + "type": [ + "number", + "null" + ], + "description": "Best bid price (0–1)" + }, + "best_ask": { + "type": [ + "number", + "null" + ], + "description": "Best ask price (0–1)" + }, + "mid_price": { + "type": [ + "number", + "null" + ], + "description": "(best_bid + best_ask) / 2" + }, + "spread": { + "type": [ + "number", + "null" + ], + "description": "best_ask − best_bid" + }, + "bid_liquidity_usd": { + "type": [ + "number", + "null" + ], + "description": "Total USD value of all bid levels" + }, + "ask_liquidity_usd": { + "type": [ + "number", + "null" + ], + "description": "Total USD value of all ask levels" + }, + "bid_levels": { + "type": [ + "integer", + "null" + ], + "description": "Number of bid price levels" + }, + "ask_levels": { + "type": [ + "integer", + "null" + ], + "description": "Number of ask price levels" + } + } + }, + "OrderBookLevel": { + "type": "array", + "description": "A single price level: [price_string, size_string]", + "items": { + "type": "string" + }, + "minItems": 2, + "maxItems": 2 + }, + "OrderBookSubscribeResponse": { + "type": "object", + "description": "Server acknowledgement for an order book subscription", + "properties": { + "condition_ids": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Accepted condition IDs" + }, + "position_ids": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Accepted position IDs" + }, + "rejected": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Filter values that were rejected (invalid format or limit exceeded)" + } + } + }, + "OrderBookSubscribeMessage": { + "type": "object", + "description": "Subscribe to the order book stream. At least one filter is required. Maximum 500 combined condition_ids + position_ids per client.", + "required": [ + "action" + ], + "properties": { + "action": { + "type": "string", + "enum": [ + "subscribe", + "unsubscribe_all" + ] + }, + "condition_ids": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Condition IDs (markets). All positions within each market are delivered.", + "maxItems": 500 + }, + "position_ids": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Token / asset IDs (individual outcome positions, hex strings).", + "maxItems": 500 + } + } + }, + "MaticUpdateEvent": { + "type": "object", + "description": "Server-pushed event: MATIC native balance change for a wallet. Envelope type: \"matic_update\". Only delivered when `include_matic: true`.", + "required": [ + "address", + "block_number", + "updated_at" + ], + "properties": { + "address": { + "type": "string", + "description": "Wallet address" + }, + "balance": { + "type": "number", + "description": "Current MATIC balance — omitted when not available" + }, + "block_number": { + "type": "integer", + "format": "uint64" + }, + "updated_at": { + "type": "integer", + "format": "int64", + "description": "Unix seconds" + } + } + }, + "TradesStreamSubscribeMessage": { + "type": "object", + "description": "Subscribe to the trades stream. At least one filter field must be non-empty.", + "required": [ + "action" + ], + "properties": { + "action": { + "type": "string", + "enum": [ + "subscribe", + "unsubscribe_all" + ] + }, + "condition_ids": { + "type": "array", + "items": { + "type": "string" + }, + "description": "64-char hex condition IDs (with or without 0x prefix)" + }, + "market_slugs": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Market slugs" + }, + "event_slugs": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Event slugs — subscribes to all markets under each event" + }, + "position_ids": { + "type": "array", + "items": { + "type": "string" + }, + "description": "ERC-1155 outcome token IDs (decimal or hex strings)" + } + } + }, + "TradesStreamSubscribeResponse": { + "type": "object", + "description": "Server acknowledgement for a trades stream subscription", + "properties": { + "condition_ids": { + "type": "array", + "items": { + "type": "string" + } + }, + "market_slugs": { + "type": "array", + "items": { + "type": "string" + } + }, + "event_slugs": { + "type": "array", + "items": { + "type": "string" + } + }, + "position_ids": { + "type": "array", + "items": { + "type": "string" + } + }, + "rejected": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Filter values that were rejected (invalid format)" + } + } + }, + "AssetPricesSubscribeMessage": { + "type": "object", + "description": "Subscribe to the asset prices stream. Empty asset_symbols = all assets.", + "required": [ + "action" + ], + "properties": { + "action": { + "type": "string", + "enum": [ + "subscribe", + "unsubscribe_all" + ] + }, + "asset_symbols": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Uppercase asset symbols (e.g. \"BTC\", \"ETH\"). Empty = subscribe to all." + } + } + }, + "AssetPricesSubscribeResponse": { + "type": "object", + "description": "Server acknowledgement for an asset prices subscription", + "properties": { + "asset_symbols": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Accepted symbols. Empty array means subscribed to all symbols." + } + } + }, + "AssetWindowUpdatesSubscribeMessage": { + "type": "object", + "description": "Subscribe to the asset window updates stream. At least one of asset_symbols or timeframes must be non-empty.", + "required": [ + "action" + ], + "properties": { + "action": { + "type": "string", + "enum": [ + "subscribe", + "unsubscribe_all" + ] + }, + "asset_symbols": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Uppercase asset symbols (e.g. \"BTC\", \"ETH\")" + }, + "timeframes": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "5m", + "15m", + "1h", + "4h", + "1d", + "24h" + ] + }, + "description": "Candle sizes to filter by. \"1d\" and \"24h\" are treated as equivalent." + } + } + }, + "AssetWindowUpdatesSubscribeResponse": { + "type": "object", + "description": "Server acknowledgement for an asset window updates subscription", + "properties": { + "asset_symbols": { + "type": "array", + "items": { + "type": "string" + } + }, + "timeframes": { + "type": "array", + "items": { + "type": "string" + } + }, + "error": { + "type": [ + "string", + "null" + ], + "description": "Set if the subscription was rejected (e.g. no filters provided)" + } + } + }, + "MarketMetricsSubscribeMessage": { + "type": "object", + "description": "Subscribe to the market metrics stream. condition_ids is required and must be non-empty.", + "required": [ + "action", + "condition_ids" + ], + "properties": { + "action": { + "type": "string", + "enum": [ + "subscribe", + "unsubscribe_all" + ] + }, + "condition_ids": { + "type": "array", + "items": { + "type": "string" + }, + "description": "64-char hex condition IDs (with or without 0x prefix)", + "minItems": 1 + } + } + }, + "MarketMetricsSubscribeResponse": { + "type": "object", + "description": "Server acknowledgement for a market metrics subscription", + "properties": { + "condition_ids": { + "type": "array", + "items": { + "type": "string" + } + }, + "rejected": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Condition IDs that were rejected (invalid format)" + }, + "error": { + "type": [ + "string", + "null" + ], + "description": "Set if the entire subscription was rejected" + } + } + }, + "EventMetricsSubscribeMessage": { + "type": "object", + "description": "Subscribe to the event metrics stream. event_slugs is required and must be non-empty.", + "required": [ + "action", + "event_slugs" + ], + "properties": { + "action": { + "type": "string", + "enum": [ + "subscribe", + "unsubscribe_all" + ] + }, + "event_slugs": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Event slugs (lowercase)", + "minItems": 1 + } + } + }, + "EventMetricsSubscribeResponse": { + "type": "object", + "description": "Server acknowledgement for an event metrics subscription", + "properties": { + "event_slugs": { + "type": "array", + "items": { + "type": "string" + } + }, + "rejected": { + "type": "array", + "items": { + "type": "string" + } + }, + "error": { + "type": [ + "string", + "null" + ] + } + } + }, + "PositionMetricsSubscribeMessage": { + "type": "object", + "description": "Subscribe to the position metrics stream. position_ids is required and must be non-empty.", + "required": [ + "action", + "position_ids" + ], + "properties": { + "action": { + "type": "string", + "enum": [ + "subscribe", + "unsubscribe_all" + ] + }, + "position_ids": { + "type": "array", + "items": { + "type": "string" + }, + "description": "ERC-1155 outcome token IDs (decimal or hex strings)", + "minItems": 1 + } + } + }, + "PositionMetricsSubscribeResponse": { + "type": "object", + "description": "Server acknowledgement for a position metrics subscription", + "properties": { + "position_ids": { + "type": "array", + "items": { + "type": "string" + } + }, + "rejected": { + "type": "array", + "items": { + "type": "string" + } + }, + "error": { + "type": [ + "string", + "null" + ] + } + } + }, + "TraderPnlSubscribeMessage": { + "type": "object", + "description": "Subscribe to the trader PnL stream. traders is required and must be non-empty.", + "required": [ + "action", + "traders" + ], + "properties": { + "action": { + "type": "string", + "enum": [ + "subscribe", + "unsubscribe_all" + ] + }, + "traders": { + "type": "array", + "items": { + "type": "string" + }, + "description": "EVM wallet addresses", + "minItems": 1 + } + } + }, + "TraderPnlSubscribeResponse": { + "type": "object", + "description": "Server acknowledgement for a trader PnL subscription", + "properties": { + "traders": { + "type": "array", + "items": { + "type": "string" + } + }, + "rejected": { + "type": "array", + "items": { + "type": "string" + } + }, + "error": { + "type": [ + "string", + "null" + ] + } + } + }, + "TradeStreamEvent": { + "type": "object", + "description": "Server-pushed event: a matched trade on a subscribed market/position/event/slug. Envelope type: \"trade_stream_update\".", + "required": [ + "trader", + "taker", + "position_id", + "trade_id", + "hash", + "block", + "confirmed_at", + "amount_usd", + "shares_amount", + "fee", + "side", + "price" + ], + "properties": { + "trader": { + "type": "string", + "description": "Limit-order maker wallet" + }, + "taker": { + "type": "string", + "description": "Order taker wallet" + }, + "position_id": { + "type": "string", + "description": "ERC-1155 outcome token ID" + }, + "condition_id": { + "type": [ + "string", + "null" + ] + }, + "outcome": { + "type": [ + "string", + "null" + ], + "description": "Outcome name (e.g. \"Yes\")" + }, + "outcome_index": { + "type": [ + "integer", + "null" + ], + "description": "0 = Yes, 1 = No" + }, + "question": { + "type": [ + "string", + "null" + ] + }, + "market_slug": { + "type": [ + "string", + "null" + ] + }, + "event_slug": { + "type": [ + "string", + "null" + ] + }, + "trade_id": { + "type": "string" + }, + "hash": { + "type": "string", + "description": "Transaction hash" + }, + "block": { + "type": "integer", + "format": "int64" + }, + "confirmed_at": { + "type": "integer", + "format": "int64", + "description": "Unix seconds" + }, + "amount_usd": { + "type": "number" + }, + "shares_amount": { + "type": "number" + }, + "fee": { + "type": "number" + }, + "side": { + "type": "string", + "enum": [ + "Buy", + "Sell" + ] + }, + "price": { + "type": "number", + "minimum": 0.0, + "maximum": 1.0 + } + } + }, + "AssetPriceTickEvent": { + "type": "object", + "description": "Server-pushed event: a crypto-asset price tick. Envelope type: \"asset_price_tick\".", + "required": [ + "symbol", + "price", + "timestamp" + ], + "properties": { + "symbol": { + "type": "string", + "description": "Uppercase asset symbol (e.g. \"BTC\")" + }, + "price": { + "type": "number", + "description": "Current price in USD" + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix milliseconds" + }, + "change_24h": { + "type": [ + "number", + "null" + ], + "description": "24-hour price change %" + }, + "volume_24h": { + "type": [ + "number", + "null" + ], + "description": "24-hour trading volume USD" + }, + "market_cap": { + "type": [ + "number", + "null" + ] + } + } + }, + "AssetPriceWindowUpdateEvent": { + "type": "object", + "description": "Server-pushed event: candle open or close for a crypto asset. Envelope type: \"asset_price_window_update\".", + "required": [ + "symbol", + "timeframe", + "update_type", + "open", + "close", + "high", + "low", + "timestamp" + ], + "properties": { + "symbol": { + "type": "string", + "description": "Uppercase asset symbol" + }, + "timeframe": { + "type": "string", + "enum": [ + "5m", + "15m", + "1h", + "4h", + "1d", + "24h" + ] + }, + "update_type": { + "type": "string", + "enum": [ + "open", + "close" + ], + "description": "\"open\" = candle starting, \"close\" = candle finalised" + }, + "open": { + "type": "number" + }, + "close": { + "type": "number" + }, + "high": { + "type": "number" + }, + "low": { + "type": "number" + }, + "volume": { + "type": [ + "number", + "null" + ] + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Candle start time in Unix milliseconds" + } + } + }, + "AssetWindowUpdateEvent": { + "allOf": [ + { + "$ref": "#/components/schemas/AssetPriceWindowUpdateEvent" + } + ], + "description": "Server-pushed event from the polymarket_asset_window_updates room. Envelope type: \"asset_window_update\"." + }, + "MetricsTimeframe": { + "type": "object", + "description": "Volume and trade-count metrics for one timeframe window", + "required": [ + "timeframe", + "volume_usd", + "trade_count" + ], + "properties": { + "timeframe": { + "type": "string", + "enum": [ + "1m", + "5m", + "30m", + "1h", + "6h", + "24h", + "7d", + "30d" + ] + }, + "volume_usd": { + "type": "number", + "description": "USD volume in this window" + }, + "trade_count": { + "type": "integer", + "description": "Number of trades in this window" + } + } + }, + "MarketMetricsEvent": { + "type": "object", + "description": "Server-pushed event: updated metrics for a condition. Envelope type: \"market_metrics_update\".", + "required": [ + "condition_id", + "timeframes" + ], + "properties": { + "condition_id": { + "type": "string", + "description": "0x-prefixed 64-char hex condition ID" + }, + "market_slug": { + "type": [ + "string", + "null" + ] + }, + "timeframes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MetricsTimeframe" + } + } + } + }, + "EventMetricsEvent": { + "type": "object", + "description": "Server-pushed event: updated aggregated metrics for an event. Envelope type: \"event_metrics_update\".", + "required": [ + "event_slug", + "timeframes" + ], + "properties": { + "event_slug": { + "type": "string" + }, + "timeframes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MetricsTimeframe" + } + } + } + }, + "PositionMetricsEvent": { + "type": "object", + "description": "Server-pushed event: updated metrics for an outcome token. Envelope type: \"position_metrics_update\".", + "required": [ + "position_id", + "timeframes" + ], + "properties": { + "position_id": { + "type": "string", + "description": "ERC-1155 token ID (decimal string)" + }, + "condition_id": { + "type": [ + "string", + "null" + ] + }, + "outcome": { + "type": [ + "string", + "null" + ] + }, + "timeframes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MetricsTimeframe" + } + } + } + }, + "PnlTimeframes": { + "type": "object", + "description": "PnL figures broken down by timeframe", + "properties": { + "1d": { + "type": [ + "number", + "null" + ], + "description": "1-day PnL in USD" + }, + "7d": { + "type": [ + "number", + "null" + ] + }, + "30d": { + "type": [ + "number", + "null" + ] + }, + "all": { + "type": [ + "number", + "null" + ], + "description": "All-time PnL in USD" + } + } + }, + "TraderGlobalPnlEvent": { + "type": "object", + "description": "Server-pushed event: global (portfolio-level) PnL update for a trader. Envelope type: \"trader_global_pnl_update\".", + "required": [ + "trader", + "realized_pnl", + "unrealized_pnl", + "timeframe" + ], + "properties": { + "trader": { + "type": "string", + "description": "Trader EVM address" + }, + "realized_pnl": { + "type": "number", + "description": "Realized PnL in USD" + }, + "unrealized_pnl": { + "type": "number", + "description": "Unrealized PnL in USD" + }, + "total_pnl": { + "type": [ + "number", + "null" + ] + }, + "timeframe": { + "type": "string", + "description": "Window that triggered the update" + }, + "updated_at": { + "type": "integer", + "format": "int64", + "description": "Unix seconds" + } + } + }, + "TraderMarketPnlEvent": { + "type": "object", + "description": "Server-pushed event: per-market PnL update for a trader. Envelope type: \"trader_market_pnl_update\".", + "required": [ + "trader", + "condition_id", + "realized_pnl", + "unrealized_pnl", + "timeframe" + ], + "properties": { + "trader": { + "type": "string" + }, + "condition_id": { + "type": "string" + }, + "market_slug": { + "type": [ + "string", + "null" + ] + }, + "realized_pnl": { + "type": "number" + }, + "unrealized_pnl": { + "type": "number" + }, + "total_pnl": { + "type": [ + "number", + "null" + ] + }, + "timeframe": { + "type": "string" + }, + "updated_at": { + "type": "integer", + "format": "int64" + } + } + }, + "TraderEventPnlEvent": { + "type": "object", + "description": "Server-pushed event: per-event PnL update for a trader. Envelope type: \"trader_event_pnl_update\".", + "required": [ + "trader", + "event_slug", + "realized_pnl", + "unrealized_pnl", + "timeframe" + ], + "properties": { + "trader": { + "type": "string" + }, + "event_slug": { + "type": "string" + }, + "realized_pnl": { + "type": "number" + }, + "unrealized_pnl": { + "type": "number" + }, + "total_pnl": { + "type": [ + "number", + "null" + ] + }, + "timeframe": { + "type": "string" + }, + "updated_at": { + "type": "integer", + "format": "int64" + } + } + }, + "AccountsSubscribeMessage": { + "type": "object", + "description": "Subscribe to the accounts stream. `wallets` is required. Share balance updates (`accounts_update`) are always delivered. Set `include_usdce` or `include_matic` to also receive those balance streams.", + "required": [ + "action", + "wallets" + ], + "properties": { + "action": { + "type": "string", + "enum": [ + "subscribe", + "unsubscribe_all" + ] + }, + "wallets": { + "type": "array", + "items": { + "type": "string" + }, + "description": "EVM wallet addresses", + "minItems": 1 + }, + "include_usdce": { + "type": "boolean", + "default": false, + "description": "Also stream USDCe collateral balance updates for subscribed wallets" + }, + "include_matic": { + "type": "boolean", + "default": false, + "description": "Also stream MATIC gas balance updates for subscribed wallets" + } + } + }, + "AccountsSubscribeResponse": { + "type": "object", + "description": "Server acknowledgement for an accounts subscription", + "properties": { + "wallets": { + "type": "array", + "items": { + "type": "string" + } + }, + "rejected": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Addresses rejected (invalid format)" + }, + "include_usdce": { + "type": "boolean" + }, + "include_matic": { + "type": "boolean" + }, + "error": { + "type": [ + "string", + "null" + ] + } + } + }, + "AccountsUpdateEvent": { + "type": "object", + "description": "Server-pushed event: ERC-1155 outcome token balance change for a wallet. Envelope type: \"accounts_update\".", + "required": [ + "wallet", + "position_id", + "balance", + "block_number", + "updated_at" + ], + "properties": { + "wallet": { + "type": "string", + "description": "Wallet address" + }, + "position_id": { + "type": "string", + "description": "ERC-1155 outcome token ID (decimal string)" + }, + "balance": { + "type": "string", + "description": "Current token balance (U256 as decimal string)" + }, + "block_number": { + "type": "integer", + "format": "int64" + }, + "updated_at": { + "type": "integer", + "format": "int64", + "description": "Unix seconds" + }, + "condition_id": { + "type": "string", + "description": "Condition ID — omitted when not available" + }, + "event_slug": { + "type": "string", + "description": "Event slug — omitted when not available" + } + } + }, + "UsdceUpdateEvent": { + "type": "object", + "description": "Server-pushed event: USDCe collateral balance change for a wallet. Envelope type: \"usdce_update\". Only delivered when `include_usdce: true`.", + "required": [ + "address", + "block_number", + "updated_at" + ], + "properties": { + "address": { + "type": "string", + "description": "Wallet address" + }, + "token_address": { + "type": "string", + "description": "USDCe contract address — omitted when not available" + }, + "balance": { + "type": "number", + "description": "Current USDCe balance — omitted when not available" + }, + "block_number": { + "type": "integer", + "format": "uint64" + }, + "updated_at": { + "type": "integer", + "format": "int64", + "description": "Unix seconds" + } + } + } + }, + "securitySchemes": { + "jwt": { + "type": "http", + "scheme": "bearer", + "bearerFormat": "JWT", + "description": "Send `{\"type\":\"authenticate\",\"jwt\":\"\"}` after connecting" + } + } + } +} \ No newline at end of file diff --git a/package.json b/package.json index 63a159b..86b5b55 100644 --- a/package.json +++ b/package.json @@ -24,14 +24,16 @@ "build": "rm -rf dist && bun build ./src/index.ts --target browser --format esm --sourcemap --outdir ./dist && bun build ./src/index.ts --target browser --format cjs --sourcemap --outdir ./dist-cjs && mv ./dist-cjs/index.js ./dist/index.cjs && mv ./dist-cjs/index.js.map ./dist/index.cjs.map && rm -rf dist-cjs && tsc --emitDeclarationOnly", "check-routes": "bun run scripts/check-routes.ts", "fix-spec": "bun run scripts/fix-spec.ts", - "prep": "bun run fetch-spec:polymarket && bun run fix-spec && bun run generate:polymarket && bun run fetch-spec:webhooks && bun run generate:webhooks && bun run check-routes && bun run build", + "prep": "bun run fetch-spec:polymarket && bun run fix-spec && bun run generate:polymarket && bun run fetch-spec:webhooks && bun run generate:webhooks && bun run fetch-spec:ws && bun run generate:ws && bun run check-routes && bun run build", "test": "bun test", "test:watch": "bun test --watch", "typecheck": "bun run tsc -p tsconfig.check.json", "fetch-spec:polymarket": "curl -s -o openapi/polymarket.json https://api.struct.to/api-docs/openapi.json", "generate:polymarket": "openapi-typescript openapi/polymarket.json -o src/generated/polymarket.ts", "fetch-spec:webhooks": "curl -s -o openapi/webhooks.json https://api.struct.to/webhookopenapi.json", - "generate:webhooks": "openapi-typescript openapi/webhooks.json -o src/generated/webhooks.ts" + "generate:webhooks": "openapi-typescript openapi/webhooks.json -o src/generated/webhooks.ts", + "fetch-spec:ws": "curl -s -o openapi/ws.json https://api.struct.to/asyncapi.json", + "generate:ws": "bun run scripts/generate-ws-types.ts" }, "devDependencies": { "@types/bun": "latest", diff --git a/scripts/check-routes.ts b/scripts/check-routes.ts index 6eebad4..b363470 100644 --- a/scripts/check-routes.ts +++ b/scripts/check-routes.ts @@ -3,6 +3,7 @@ import { join } from "node:path"; const NAMESPACES_DIR = join(import.meta.dirname, "../src/namespaces"); const TYPES_FILE = join(import.meta.dirname, "../src/types/index.ts"); +const WS_TYPES_FILE = join(import.meta.dirname, "../src/types/ws.ts"); interface SpecConfig { specPath: string; @@ -114,15 +115,37 @@ async function getExportedSchemas(typesContent: string): Promise> { const exported = new Set(); for (const m of typesContent.matchAll(/Schemas\["(\w+)"\]/g)) exported.add(m[1]); for (const m of typesContent.matchAll(/WebhookSchemas\["(\w+)"\]/g)) exported.add(m[1]); + for (const m of typesContent.matchAll(/WsSchemas\["(\w+)"\]/g)) exported.add(m[1]); for (const m of typesContent.matchAll(/export type (\w+)\s*=/g)) exported.add(m[1]); for (const m of typesContent.matchAll(/export interface (\w+)/g)) exported.add(m[1]); return exported; } +async function getWsSpecRooms(jsonSpecPath: string): Promise { + const spec = JSON.parse(await readFile(jsonSpecPath, "utf-8")); + return Object.keys(spec.channels ?? {}); +} + +async function getSdkWsRooms(): Promise> { + const content = await readFile(WS_TYPES_FILE, "utf-8"); + const rooms = new Set(); + const subscriptionMapMatch = content.match(/interface WsSubscriptionMap\s*\{([^}]+)\}/); + if (subscriptionMapMatch) { + const regex = /(\w+)\s*:/g; + let match: RegExpExecArray | null; + while ((match = regex.exec(subscriptionMapMatch[1])) !== null) { + rooms.add(match[1]); + } + } + return rooms; +} + let hasErrors = false; const typesContent = await readFile(TYPES_FILE, "utf-8"); -const exportedSchemas = await getExportedSchemas(typesContent); +const wsTypesContent = await readFile(join(import.meta.dirname, "../src/types/ws.ts"), "utf-8"); +const combinedTypesContent = typesContent + "\n" + wsTypesContent; +const exportedSchemas = await getExportedSchemas(combinedTypesContent); for (const config of specs) { const specName = config.venuePrefix ?? "platform"; @@ -176,4 +199,47 @@ for (const config of specs) { } } +const wsJsonPath = join(import.meta.dirname, "../openapi/ws.json"); +const wsSpecRooms = await getWsSpecRooms(wsJsonPath); +const sdkWsRooms = await getSdkWsRooms(); + +const phantomWsRooms = [...sdkWsRooms].filter((r) => !wsSpecRooms.includes(r)); +const missingWsRooms = wsSpecRooms.filter((r) => !sdkWsRooms.has(r)); + +if (phantomWsRooms.length > 0) { + hasErrors = true; + console.error(`\x1b[31m✗ [ws] Phantom rooms (SDK rooms not in WS OpenAPI spec):\x1b[0m\n`); + for (const r of phantomWsRooms) { + console.error(` ${r}`); + } + console.error(); +} + +if (missingWsRooms.length > 0) { + hasErrors = true; + console.error(`\x1b[31m✗ [ws] Unimplemented rooms (WS OpenAPI spec rooms missing from SDK):\x1b[0m\n`); + for (const r of missingWsRooms) { + console.error(` ${r}`); + } + console.error(); +} + +if (phantomWsRooms.length === 0 && missingWsRooms.length === 0) { + console.log(`\x1b[32m✓ [ws] All SDK rooms match the WS OpenAPI spec.\x1b[0m`); +} + +const wsSpecSchemas = await getSpecSchemas(wsJsonPath); +const missingWsSchemas = wsSpecSchemas.filter((s) => !exportedSchemas.has(s)); + +if (missingWsSchemas.length > 0) { + hasErrors = true; + console.error(`\x1b[31m✗ [ws] Missing schema exports:\x1b[0m\n`); + for (const schema of missingWsSchemas) { + console.error(` WsSchemas["${schema}"]`); + } + console.error(); +} else { + console.log(`\x1b[32m✓ [ws] All WS schemas exported.\x1b[0m`); +} + process.exit(hasErrors ? 1 : 0); diff --git a/scripts/generate-ws-types.ts b/scripts/generate-ws-types.ts new file mode 100644 index 0000000..faddc34 --- /dev/null +++ b/scripts/generate-ws-types.ts @@ -0,0 +1,18 @@ +import openapiTS, { astToString } from "openapi-typescript"; +import { readFile, writeFile } from "node:fs/promises"; +import { join } from "node:path"; + +const asyncapiPath = join(import.meta.dirname, "../openapi/ws.json"); +const outputPath = join(import.meta.dirname, "../src/generated/ws.ts"); + +const asyncapi = JSON.parse(await readFile(asyncapiPath, "utf-8")); + +const ast = await openapiTS({ + openapi: "3.1.0", + info: asyncapi.info, + paths: {}, + components: { schemas: asyncapi.components.schemas }, +}); + +await writeFile(outputPath, astToString(ast)); +console.log("✓ Generated WS types from AsyncAPI spec"); diff --git a/src/generated/ws.ts b/src/generated/ws.ts new file mode 100644 index 0000000..0b01c37 --- /dev/null +++ b/src/generated/ws.ts @@ -0,0 +1,399 @@ +export type paths = Record; +export type webhooks = Record; +export interface components { + schemas: { + /** @description Server-pushed event: full CLOB orderbook snapshot for an outcome token. Envelope type: "order_book_update". Delivered whenever the book changes for a subscribed condition or position. */ + OrderBookUpdateEvent: { + /** @description Hex token ID (position / outcome token) */ + asset_id: string; + /** @description Condition ID (hex) */ + market: string; + /** @description Bid levels sorted best-first (highest price first) */ + bids: components["schemas"]["OrderBookLevel"][]; + /** @description Ask levels sorted best-first (lowest price first) */ + asks: components["schemas"]["OrderBookLevel"][]; + /** + * Format: int64 + * @description Unix milliseconds from CLOB message + */ + timestamp: number; + /** @description Orderbook content hash — identical hash means no change */ + hash: string; + /** @description Best bid price (0–1) */ + best_bid?: number | null; + /** @description Best ask price (0–1) */ + best_ask?: number | null; + /** @description (best_bid + best_ask) / 2 */ + mid_price?: number | null; + /** @description best_ask − best_bid */ + spread?: number | null; + /** @description Total USD value of all bid levels */ + bid_liquidity_usd?: number | null; + /** @description Total USD value of all ask levels */ + ask_liquidity_usd?: number | null; + /** @description Number of bid price levels */ + bid_levels?: number | null; + /** @description Number of ask price levels */ + ask_levels?: number | null; + }; + /** @description A single price level: [price_string, size_string] */ + OrderBookLevel: string[]; + /** @description Server acknowledgement for an order book subscription */ + OrderBookSubscribeResponse: { + /** @description Accepted condition IDs */ + condition_ids?: string[]; + /** @description Accepted position IDs */ + position_ids?: string[]; + /** @description Filter values that were rejected (invalid format or limit exceeded) */ + rejected?: string[]; + }; + /** @description Subscribe to the order book stream. At least one filter is required. Maximum 500 combined condition_ids + position_ids per client. */ + OrderBookSubscribeMessage: { + /** @enum {string} */ + action: "subscribe" | "unsubscribe_all"; + /** @description Condition IDs (markets). All positions within each market are delivered. */ + condition_ids?: string[]; + /** @description Token / asset IDs (individual outcome positions, hex strings). */ + position_ids?: string[]; + }; + /** @description Server-pushed event: MATIC native balance change for a wallet. Envelope type: "matic_update". Only delivered when `include_matic: true`. */ + MaticUpdateEvent: { + /** @description Wallet address */ + address: string; + /** @description Current MATIC balance — omitted when not available */ + balance?: number; + /** Format: uint64 */ + block_number: number; + /** + * Format: int64 + * @description Unix seconds + */ + updated_at: number; + }; + /** @description Subscribe to the trades stream. At least one filter field must be non-empty. */ + TradesStreamSubscribeMessage: { + /** @enum {string} */ + action: "subscribe" | "unsubscribe_all"; + /** @description 64-char hex condition IDs (with or without 0x prefix) */ + condition_ids?: string[]; + /** @description Market slugs */ + market_slugs?: string[]; + /** @description Event slugs — subscribes to all markets under each event */ + event_slugs?: string[]; + /** @description ERC-1155 outcome token IDs (decimal or hex strings) */ + position_ids?: string[]; + }; + /** @description Server acknowledgement for a trades stream subscription */ + TradesStreamSubscribeResponse: { + condition_ids?: string[]; + market_slugs?: string[]; + event_slugs?: string[]; + position_ids?: string[]; + /** @description Filter values that were rejected (invalid format) */ + rejected?: string[]; + }; + /** @description Subscribe to the asset prices stream. Empty asset_symbols = all assets. */ + AssetPricesSubscribeMessage: { + /** @enum {string} */ + action: "subscribe" | "unsubscribe_all"; + /** @description Uppercase asset symbols (e.g. "BTC", "ETH"). Empty = subscribe to all. */ + asset_symbols?: string[]; + }; + /** @description Server acknowledgement for an asset prices subscription */ + AssetPricesSubscribeResponse: { + /** @description Accepted symbols. Empty array means subscribed to all symbols. */ + asset_symbols?: string[]; + }; + /** @description Subscribe to the asset window updates stream. At least one of asset_symbols or timeframes must be non-empty. */ + AssetWindowUpdatesSubscribeMessage: { + /** @enum {string} */ + action: "subscribe" | "unsubscribe_all"; + /** @description Uppercase asset symbols (e.g. "BTC", "ETH") */ + asset_symbols?: string[]; + /** @description Candle sizes to filter by. "1d" and "24h" are treated as equivalent. */ + timeframes?: ("5m" | "15m" | "1h" | "4h" | "1d" | "24h")[]; + }; + /** @description Server acknowledgement for an asset window updates subscription */ + AssetWindowUpdatesSubscribeResponse: { + asset_symbols?: string[]; + timeframes?: string[]; + /** @description Set if the subscription was rejected (e.g. no filters provided) */ + error?: string | null; + }; + /** @description Subscribe to the market metrics stream. condition_ids is required and must be non-empty. */ + MarketMetricsSubscribeMessage: { + /** @enum {string} */ + action: "subscribe" | "unsubscribe_all"; + /** @description 64-char hex condition IDs (with or without 0x prefix) */ + condition_ids: string[]; + }; + /** @description Server acknowledgement for a market metrics subscription */ + MarketMetricsSubscribeResponse: { + condition_ids?: string[]; + /** @description Condition IDs that were rejected (invalid format) */ + rejected?: string[]; + /** @description Set if the entire subscription was rejected */ + error?: string | null; + }; + /** @description Subscribe to the event metrics stream. event_slugs is required and must be non-empty. */ + EventMetricsSubscribeMessage: { + /** @enum {string} */ + action: "subscribe" | "unsubscribe_all"; + /** @description Event slugs (lowercase) */ + event_slugs: string[]; + }; + /** @description Server acknowledgement for an event metrics subscription */ + EventMetricsSubscribeResponse: { + event_slugs?: string[]; + rejected?: string[]; + error?: string | null; + }; + /** @description Subscribe to the position metrics stream. position_ids is required and must be non-empty. */ + PositionMetricsSubscribeMessage: { + /** @enum {string} */ + action: "subscribe" | "unsubscribe_all"; + /** @description ERC-1155 outcome token IDs (decimal or hex strings) */ + position_ids: string[]; + }; + /** @description Server acknowledgement for a position metrics subscription */ + PositionMetricsSubscribeResponse: { + position_ids?: string[]; + rejected?: string[]; + error?: string | null; + }; + /** @description Subscribe to the trader PnL stream. traders is required and must be non-empty. */ + TraderPnlSubscribeMessage: { + /** @enum {string} */ + action: "subscribe" | "unsubscribe_all"; + /** @description EVM wallet addresses */ + traders: string[]; + }; + /** @description Server acknowledgement for a trader PnL subscription */ + TraderPnlSubscribeResponse: { + traders?: string[]; + rejected?: string[]; + error?: string | null; + }; + /** @description Server-pushed event: a matched trade on a subscribed market/position/event/slug. Envelope type: "trade_stream_update". */ + TradeStreamEvent: { + /** @description Limit-order maker wallet */ + trader: string; + /** @description Order taker wallet */ + taker: string; + /** @description ERC-1155 outcome token ID */ + position_id: string; + condition_id?: string | null; + /** @description Outcome name (e.g. "Yes") */ + outcome?: string | null; + /** @description 0 = Yes, 1 = No */ + outcome_index?: number | null; + question?: string | null; + market_slug?: string | null; + event_slug?: string | null; + trade_id: string; + /** @description Transaction hash */ + hash: string; + /** Format: int64 */ + block: number; + /** + * Format: int64 + * @description Unix seconds + */ + confirmed_at: number; + amount_usd: number; + shares_amount: number; + fee: number; + /** @enum {string} */ + side: "Buy" | "Sell"; + price: number; + }; + /** @description Server-pushed event: a crypto-asset price tick. Envelope type: "asset_price_tick". */ + AssetPriceTickEvent: { + /** @description Uppercase asset symbol (e.g. "BTC") */ + symbol: string; + /** @description Current price in USD */ + price: number; + /** + * Format: int64 + * @description Unix milliseconds + */ + timestamp: number; + /** @description 24-hour price change % */ + change_24h?: number | null; + /** @description 24-hour trading volume USD */ + volume_24h?: number | null; + market_cap?: number | null; + }; + /** @description Server-pushed event: candle open or close for a crypto asset. Envelope type: "asset_price_window_update". */ + AssetPriceWindowUpdateEvent: { + /** @description Uppercase asset symbol */ + symbol: string; + /** @enum {string} */ + timeframe: "5m" | "15m" | "1h" | "4h" | "1d" | "24h"; + /** + * @description "open" = candle starting, "close" = candle finalised + * @enum {string} + */ + update_type: "open" | "close"; + open: number; + close: number; + high: number; + low: number; + volume?: number | null; + /** + * Format: int64 + * @description Candle start time in Unix milliseconds + */ + timestamp: number; + }; + /** @description Server-pushed event from the polymarket_asset_window_updates room. Envelope type: "asset_window_update". */ + AssetWindowUpdateEvent: components["schemas"]["AssetPriceWindowUpdateEvent"]; + /** @description Volume and trade-count metrics for one timeframe window */ + MetricsTimeframe: { + /** @enum {string} */ + timeframe: "1m" | "5m" | "30m" | "1h" | "6h" | "24h" | "7d" | "30d"; + /** @description USD volume in this window */ + volume_usd: number; + /** @description Number of trades in this window */ + trade_count: number; + }; + /** @description Server-pushed event: updated metrics for a condition. Envelope type: "market_metrics_update". */ + MarketMetricsEvent: { + /** @description 0x-prefixed 64-char hex condition ID */ + condition_id: string; + market_slug?: string | null; + timeframes: components["schemas"]["MetricsTimeframe"][]; + }; + /** @description Server-pushed event: updated aggregated metrics for an event. Envelope type: "event_metrics_update". */ + EventMetricsEvent: { + event_slug: string; + timeframes: components["schemas"]["MetricsTimeframe"][]; + }; + /** @description Server-pushed event: updated metrics for an outcome token. Envelope type: "position_metrics_update". */ + PositionMetricsEvent: { + /** @description ERC-1155 token ID (decimal string) */ + position_id: string; + condition_id?: string | null; + outcome?: string | null; + timeframes: components["schemas"]["MetricsTimeframe"][]; + }; + /** @description PnL figures broken down by timeframe */ + PnlTimeframes: { + /** @description 1-day PnL in USD */ + "1d"?: number | null; + "7d"?: number | null; + "30d"?: number | null; + /** @description All-time PnL in USD */ + all?: number | null; + }; + /** @description Server-pushed event: global (portfolio-level) PnL update for a trader. Envelope type: "trader_global_pnl_update". */ + TraderGlobalPnlEvent: { + /** @description Trader EVM address */ + trader: string; + /** @description Realized PnL in USD */ + realized_pnl: number; + /** @description Unrealized PnL in USD */ + unrealized_pnl: number; + total_pnl?: number | null; + /** @description Window that triggered the update */ + timeframe: string; + /** + * Format: int64 + * @description Unix seconds + */ + updated_at?: number; + }; + /** @description Server-pushed event: per-market PnL update for a trader. Envelope type: "trader_market_pnl_update". */ + TraderMarketPnlEvent: { + trader: string; + condition_id: string; + market_slug?: string | null; + realized_pnl: number; + unrealized_pnl: number; + total_pnl?: number | null; + timeframe: string; + /** Format: int64 */ + updated_at?: number; + }; + /** @description Server-pushed event: per-event PnL update for a trader. Envelope type: "trader_event_pnl_update". */ + TraderEventPnlEvent: { + trader: string; + event_slug: string; + realized_pnl: number; + unrealized_pnl: number; + total_pnl?: number | null; + timeframe: string; + /** Format: int64 */ + updated_at?: number; + }; + /** @description Subscribe to the accounts stream. `wallets` is required. Share balance updates (`accounts_update`) are always delivered. Set `include_usdce` or `include_matic` to also receive those balance streams. */ + AccountsSubscribeMessage: { + /** @enum {string} */ + action: "subscribe" | "unsubscribe_all"; + /** @description EVM wallet addresses */ + wallets: string[]; + /** + * @description Also stream USDCe collateral balance updates for subscribed wallets + * @default false + */ + include_usdce: boolean; + /** + * @description Also stream MATIC gas balance updates for subscribed wallets + * @default false + */ + include_matic: boolean; + }; + /** @description Server acknowledgement for an accounts subscription */ + AccountsSubscribeResponse: { + wallets?: string[]; + /** @description Addresses rejected (invalid format) */ + rejected?: string[]; + include_usdce?: boolean; + include_matic?: boolean; + error?: string | null; + }; + /** @description Server-pushed event: ERC-1155 outcome token balance change for a wallet. Envelope type: "accounts_update". */ + AccountsUpdateEvent: { + /** @description Wallet address */ + wallet: string; + /** @description ERC-1155 outcome token ID (decimal string) */ + position_id: string; + /** @description Current token balance (U256 as decimal string) */ + balance: string; + /** Format: int64 */ + block_number: number; + /** + * Format: int64 + * @description Unix seconds + */ + updated_at: number; + /** @description Condition ID — omitted when not available */ + condition_id?: string; + /** @description Event slug — omitted when not available */ + event_slug?: string; + }; + /** @description Server-pushed event: USDCe collateral balance change for a wallet. Envelope type: "usdce_update". Only delivered when `include_usdce: true`. */ + UsdceUpdateEvent: { + /** @description Wallet address */ + address: string; + /** @description USDCe contract address — omitted when not available */ + token_address?: string; + /** @description Current USDCe balance — omitted when not available */ + balance?: number; + /** Format: uint64 */ + block_number: number; + /** + * Format: int64 + * @description Unix seconds + */ + updated_at: number; + }; + }; + responses: never; + parameters: never; + requestBodies: never; + headers: never; + pathItems: never; +} +export type $defs = Record; +export type operations = Record; diff --git a/src/types/index.ts b/src/types/index.ts index 61de6d9..ce3accb 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -12,6 +12,10 @@ export type { operations as WebhookOperations, paths as WebhookPaths, } from "../generated/webhooks.js"; +export type { WsSchemas } from "./ws-helpers.js"; +export type { + components as WsComponents, +} from "../generated/ws.js"; import type { Schemas, OperationQuery } from "./helpers.js"; import type { WebhookSchemas, WebhookOperationQuery, WebhookOperationRequestBody } from "./webhook-helpers.js"; @@ -385,11 +389,45 @@ export type { Address, PaginationParams, SortParams, Venue } from "./common.js"; export type { ConnectionState, StructWebSocketConfig, - PredictionTrade, - EnrichedPredictionTrade, - PredictionMarketMetadata, - PredictionWalletTrackingAlert, + WsRoomId, + WsFiltersOptionalRoom, + WsFiltersRequiredRoom, WebSocketEventMap, - WebSocketMessage, - WebSocketServerMessage, + WsSubscriptionMap, + WsSubscribeResponseMap, + TradesSubscribeFilters, + AssetPricesSubscribeFilters, + AssetWindowUpdatesSubscribeFilters, + MarketMetricsSubscribeFilters, + EventMetricsSubscribeFilters, + PositionMetricsSubscribeFilters, + TraderPnlSubscribeFilters, + AccountsSubscribeFilters, + OrderBookSubscribeFilters, + TradeStreamEvent, + AssetPriceTickEvent, + AssetPriceWindowUpdateEvent, + AssetWindowUpdateEvent, + WsMetricsTimeframe, + MarketMetricsEvent, + EventMetricsEvent, + PositionMetricsEvent, + WsPnlTimeframes, + TraderGlobalPnlEvent, + TraderMarketPnlEvent, + TraderEventPnlEvent, + AccountsUpdateEvent, + UsdceUpdateEvent, + MaticUpdateEvent, + WsOrderBookLevel, + OrderBookUpdateEvent, + TradesStreamSubscribeResponse, + AssetPricesSubscribeResponse, + AssetWindowUpdatesSubscribeResponse, + MarketMetricsSubscribeResponse, + EventMetricsSubscribeResponse, + PositionMetricsSubscribeResponse, + TraderPnlSubscribeResponse, + AccountsSubscribeResponse, + OrderBookSubscribeResponse, } from "./ws.js"; diff --git a/src/types/ws-helpers.ts b/src/types/ws-helpers.ts new file mode 100644 index 0000000..a72eea8 --- /dev/null +++ b/src/types/ws-helpers.ts @@ -0,0 +1,3 @@ +import type { components } from "../generated/ws.js"; + +export type WsSchemas = components["schemas"]; diff --git a/src/types/ws.ts b/src/types/ws.ts index 7652a15..d8602b4 100644 --- a/src/types/ws.ts +++ b/src/types/ws.ts @@ -1,114 +1,109 @@ -import type { Address } from "./common.js"; import type { RetryConfig } from "./http.js"; +import type { WsSchemas } from "./ws-helpers.js"; export type ConnectionState = "disconnected" | "connecting" | "connected" | "reconnecting"; export interface StructWebSocketConfig { apiKey: string; - baseUrl?: string; + wsUrl?: string; reconnect?: RetryConfig; + subscribeTimeout?: number; } -export interface PredictionTrade { - id: string; - hash: string; - chain_id: number; - block: number; - confirmed_at: number; - log_index: number; - block_index?: number; - order_hash?: string; - trader: Address; - taker: Address; - side: number; - condition_id: string | null; - position_id: string; - outcome: string | null; - outcome_index: number | null; - question: string | null; - slug: string | null; - event_slug?: string | null; - usd_amount: string; - shares_amount: string; - price: number; - probability: number | null; - fee?: string; - exchange?: number; - trade_type?: number; -} +export type WsRoomId = + | "polymarket_trades" + | "polymarket_asset_prices" + | "polymarket_asset_window_updates" + | "polymarket_market_metrics" + | "polymarket_event_metrics" + | "polymarket_position_metrics" + | "polymarket_trader_pnl" + | "polymarket_accounts" + | "polymarket_order_book"; -export interface EnrichedPredictionTrade { - id: string; - hash: string; - block: number; - confirmed_at: number; - trader: Address; - side: number; - position_id: string; - condition_id: string | null; - outcome: string | null; - outcome_index: number | null; - question: string; - slug: string; - event_slug: string; - image_url: string | null; - market_id: string | null; - title: string | null; - usd_amount: string; - shares_amount: string; - price: number; - probability: number | null; - smart_money_score: number; - insider_score: number; - categories: string[]; -} +export type WsFiltersOptionalRoom = "polymarket_asset_prices"; +export type WsFiltersRequiredRoom = Exclude; -export interface PredictionMarketMetadata { - slug: string | null; - question: string | null; - outcome: string | null; - outcome_index?: number | null; - image_url?: string | null; -} +export type TradesSubscribeFilters = Omit; +export type AssetPricesSubscribeFilters = Omit; +export type AssetWindowUpdatesSubscribeFilters = Omit; +export type MarketMetricsSubscribeFilters = Omit; +export type EventMetricsSubscribeFilters = Omit; +export type PositionMetricsSubscribeFilters = Omit; +export type TraderPnlSubscribeFilters = Omit; +export type AccountsSubscribeFilters = Pick & + Partial>; +export type OrderBookSubscribeFilters = Omit; -export interface PredictionWalletTrackingAlert { - is_buy: boolean; - trader: Address; - condition_id: string | null; - position_id: string; - usd_amount: string; - shares_amount: string; - price: number; - probability: number | null; - metadata: PredictionMarketMetadata | null; - confirmed_at: number; -} +export type TradeStreamEvent = WsSchemas["TradeStreamEvent"]; +export type AssetPriceTickEvent = WsSchemas["AssetPriceTickEvent"]; +export type AssetPriceWindowUpdateEvent = WsSchemas["AssetPriceWindowUpdateEvent"]; +export type AssetWindowUpdateEvent = WsSchemas["AssetWindowUpdateEvent"]; +export type WsMetricsTimeframe = WsSchemas["MetricsTimeframe"]; +export type MarketMetricsEvent = WsSchemas["MarketMetricsEvent"]; +export type EventMetricsEvent = WsSchemas["EventMetricsEvent"]; +export type PositionMetricsEvent = WsSchemas["PositionMetricsEvent"]; +export type WsPnlTimeframes = WsSchemas["PnlTimeframes"]; +export type TraderGlobalPnlEvent = WsSchemas["TraderGlobalPnlEvent"]; +export type TraderMarketPnlEvent = WsSchemas["TraderMarketPnlEvent"]; +export type TraderEventPnlEvent = WsSchemas["TraderEventPnlEvent"]; +export type AccountsUpdateEvent = WsSchemas["AccountsUpdateEvent"]; +export type UsdceUpdateEvent = WsSchemas["UsdceUpdateEvent"]; +export type MaticUpdateEvent = WsSchemas["MaticUpdateEvent"]; +export type WsOrderBookLevel = WsSchemas["OrderBookLevel"]; +export type OrderBookUpdateEvent = WsSchemas["OrderBookUpdateEvent"]; + +export type TradesStreamSubscribeResponse = WsSchemas["TradesStreamSubscribeResponse"]; +export type AssetPricesSubscribeResponse = WsSchemas["AssetPricesSubscribeResponse"]; +export type AssetWindowUpdatesSubscribeResponse = WsSchemas["AssetWindowUpdatesSubscribeResponse"]; +export type MarketMetricsSubscribeResponse = WsSchemas["MarketMetricsSubscribeResponse"]; +export type EventMetricsSubscribeResponse = WsSchemas["EventMetricsSubscribeResponse"]; +export type PositionMetricsSubscribeResponse = WsSchemas["PositionMetricsSubscribeResponse"]; +export type TraderPnlSubscribeResponse = WsSchemas["TraderPnlSubscribeResponse"]; +export type AccountsSubscribeResponse = WsSchemas["AccountsSubscribeResponse"]; +export type OrderBookSubscribeResponse = WsSchemas["OrderBookSubscribeResponse"]; export interface WebSocketEventMap { - market_trade: PredictionTrade; - whale_trade: EnrichedPredictionTrade; - smart_money_trade: EnrichedPredictionTrade; - insider_trade: EnrichedPredictionTrade; - wallet_tracking_alert: PredictionWalletTrackingAlert; - conditions_tracking_alert: PredictionTrade; + trade_stream_update: TradeStreamEvent; + asset_price_tick: AssetPriceTickEvent; + asset_price_window_update: AssetPriceWindowUpdateEvent; + asset_window_update: AssetWindowUpdateEvent; + market_metrics_update: MarketMetricsEvent; + event_metrics_update: EventMetricsEvent; + position_metrics_update: PositionMetricsEvent; + trader_global_pnl_update: TraderGlobalPnlEvent; + trader_market_pnl_update: TraderMarketPnlEvent; + trader_event_pnl_update: TraderEventPnlEvent; + accounts_update: AccountsUpdateEvent; + usdce_update: UsdceUpdateEvent; + matic_update: MaticUpdateEvent; + order_book_update: OrderBookUpdateEvent; connected: void; disconnected: { code: number; reason: string }; reconnecting: { attempt: number }; error: Error; } -export interface WebSocketMessage { - type: string; - room_id?: string; - action?: string; - message?: Record; - wallet_addresses?: string[]; - condition_ids?: string[]; +export interface WsSubscriptionMap { + polymarket_trades: TradesSubscribeFilters; + polymarket_asset_prices: AssetPricesSubscribeFilters; + polymarket_asset_window_updates: AssetWindowUpdatesSubscribeFilters; + polymarket_market_metrics: MarketMetricsSubscribeFilters; + polymarket_event_metrics: EventMetricsSubscribeFilters; + polymarket_position_metrics: PositionMetricsSubscribeFilters; + polymarket_trader_pnl: TraderPnlSubscribeFilters; + polymarket_accounts: AccountsSubscribeFilters; + polymarket_order_book: OrderBookSubscribeFilters; } -export interface WebSocketServerMessage { - type: string; - data?: unknown; - room_id?: string; - message?: string; +export interface WsSubscribeResponseMap { + polymarket_trades: TradesStreamSubscribeResponse; + polymarket_asset_prices: AssetPricesSubscribeResponse; + polymarket_asset_window_updates: AssetWindowUpdatesSubscribeResponse; + polymarket_market_metrics: MarketMetricsSubscribeResponse; + polymarket_event_metrics: EventMetricsSubscribeResponse; + polymarket_position_metrics: PositionMetricsSubscribeResponse; + polymarket_trader_pnl: TraderPnlSubscribeResponse; + polymarket_accounts: AccountsSubscribeResponse; + polymarket_order_book: OrderBookSubscribeResponse; } diff --git a/src/ws-transport.ts b/src/ws-transport.ts index 82d8c59..8cb7761 100644 --- a/src/ws-transport.ts +++ b/src/ws-transport.ts @@ -1,5 +1,5 @@ import { WebSocketError, WebSocketClosedError } from "./errors.js"; -import type { ConnectionState, WebSocketMessage } from "./types/ws.js"; +import type { ConnectionState } from "./types/ws.js"; import type { RetryConfig } from "./types/http.js"; const DEFAULT_INITIAL_DELAY_MS = 1_000; @@ -19,8 +19,10 @@ export class WebSocketTransport { private reconnectTimer: ReturnType | null = null; private reconnectAttempt = 0; private intentionalClose = false; - private readonly pendingMessages: WebSocketMessage[] = []; - private readonly replayMessages: WebSocketMessage[] = []; + private connectResolve: (() => void) | null = null; + private connectReject: ((err: Error) => void) | null = null; + private readonly pendingMessages: Record[] = []; + private readonly replayMessages: Record[] = []; private readonly url: string; private readonly retry: RetryConfig; private readonly callbacks: WebSocketTransportCallbacks; @@ -35,17 +37,28 @@ export class WebSocketTransport { return this._state; } - connect(): void { - if (this._state === "connected" || this._state === "connecting" || this._state === "reconnecting") { - return; - } - if (this.ws && (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING)) { - return; + connect(): Promise { + if (this._state === "connected") return Promise.resolve(); + if (this._state === "connecting" || this._state === "reconnecting") { + return new Promise((resolve, reject) => { + const prevResolve = this.connectResolve; + const prevReject = this.connectReject; + this.connectResolve = () => { prevResolve?.(); resolve(); }; + this.connectReject = (err) => { prevReject?.(err); reject(err); }; + }); } + this.intentionalClose = false; this.clearReconnectTimer(); this.setState("connecting"); + + const promise = new Promise((resolve, reject) => { + this.connectResolve = resolve; + this.connectReject = reject; + }); + this.createSocket(); + return promise; } disconnect(): void { @@ -53,6 +66,7 @@ export class WebSocketTransport { this.clearReconnectTimer(); this.pendingMessages.length = 0; this.replayMessages.length = 0; + this.resolveConnect(new WebSocketClosedError(1000, "client disconnect")); if (this.ws) { this.ws.close(1000, "client disconnect"); this.ws = null; @@ -60,7 +74,7 @@ export class WebSocketTransport { this.setState("disconnected"); } - send(message: WebSocketMessage): void { + send(message: Record): void { if (this._state === "connected" && this.ws?.readyState === WebSocket.OPEN) { this.ws.send(JSON.stringify(message)); } else { @@ -68,29 +82,31 @@ export class WebSocketTransport { } } - addReplayMessage(message: WebSocketMessage): void { + addReplayMessage(message: Record): void { this.replayMessages.push(message); } - removeReplayMessages(predicate: (msg: WebSocketMessage) => boolean): void { - for (let i = this.replayMessages.length - 1; i >= 0; i--) { - if (predicate(this.replayMessages[i]!)) { - this.replayMessages.splice(i, 1); - } - } - } - clearReplayMessages(): void { this.replayMessages.length = 0; } + private resolveConnect(error?: Error): void { + if (error) { + this.connectReject?.(error); + } else { + this.connectResolve?.(); + } + this.connectResolve = null; + this.connectReject = null; + } + private createSocket(): void { try { this.ws = new WebSocket(this.url); } catch (err) { - this.callbacks.onError( - new WebSocketError("Failed to create WebSocket", { cause: err }), - ); + const error = new WebSocketError("Failed to create WebSocket", { cause: err }); + this.callbacks.onError(error); + this.resolveConnect(error); this.scheduleReconnect(); return; } @@ -100,6 +116,7 @@ export class WebSocketTransport { this.reconnectAttempt = 0; this.replaySubscriptions(); this.flushPendingMessages(); + this.resolveConnect(); this.callbacks.onOpen(); }; @@ -110,6 +127,7 @@ export class WebSocketTransport { this.callbacks.onClose(event.code, event.reason); return; } + this.resolveConnect(new WebSocketClosedError(event.code, event.reason)); this.callbacks.onClose(event.code, event.reason); this.scheduleReconnect(); }; diff --git a/src/ws.ts b/src/ws.ts index 746343e..e73aa4f 100644 --- a/src/ws.ts +++ b/src/ws.ts @@ -1,30 +1,40 @@ import { WebSocketTransport } from "./ws-transport.js"; +import { WebSocketError } from "./errors.js"; import type { ConnectionState, StructWebSocketConfig, WebSocketEventMap, - WebSocketMessage, - WebSocketServerMessage, + WsRoomId, + WsFiltersOptionalRoom, + WsFiltersRequiredRoom, + WsSubscriptionMap, + WsSubscribeResponseMap, } from "./types/ws.js"; -import type { Address } from "./types/common.js"; -const DEFAULT_BASE_URL = "https://api.struct.to/v1"; +const DEFAULT_WS_URL = "wss://api.struct.to/ws"; +const PING_INTERVAL_MS = 30_000; +const DEFAULT_SUBSCRIBE_TIMEOUT_MS = 10_000; type Listener = (payload: T) => void; +interface PendingSubscribe { + resolve: (data: unknown) => void; + reject: (err: Error) => void; + timer: ReturnType; +} + export class StructWebSocket { private readonly transport: WebSocketTransport; private readonly listeners = new Map>(); - private readonly activeMarkets = new Set(); - private readonly activeMarketPositions = new Set(); - private readonly activeWallets = new Set(); - private readonly activeConditions = new Set(); - private readonly activeSpecialRooms = new Set(); + private readonly subscriptions = new Map>(); + private readonly pendingSubscribes = new Map(); + private readonly subscribeTimeout: number; + private pingTimer: ReturnType | null = null; constructor(config: StructWebSocketConfig) { - const httpBase = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, ""); - const wsBase = httpBase.replace(/^https:\/\//, "wss://").replace(/^http:\/\//, "ws://"); - const url = `${wsBase}?token=${encodeURIComponent(config.apiKey)}`; + this.subscribeTimeout = config.subscribeTimeout ?? DEFAULT_SUBSCRIBE_TIMEOUT_MS; + const wsUrl = (config.wsUrl ?? DEFAULT_WS_URL).replace(/\/+$/, ""); + const url = `${wsUrl}?token=${encodeURIComponent(config.apiKey)}`; this.transport = new WebSocketTransport( url, @@ -43,35 +53,36 @@ export class StructWebSocket { return this.transport.state; } - connect(): void { - this.transport.connect(); + connect(): Promise { + return this.transport.connect(); } disconnect(): void { - this.activeMarkets.clear(); - this.activeMarketPositions.clear(); - this.activeWallets.clear(); - this.activeConditions.clear(); - this.activeSpecialRooms.clear(); + this.stopPing(); + for (const [, pending] of this.pendingSubscribes) { + clearTimeout(pending.timer); + pending.reject(new WebSocketError("Disconnected")); + } + this.pendingSubscribes.clear(); + this.subscriptions.clear(); this.transport.disconnect(); } - on(event: K, listener: Listener): this { + on(event: K, listener: Listener): () => void { let set = this.listeners.get(event as string); if (!set) { set = new Set(); this.listeners.set(event as string, set); } set.add(listener); - return this; + return () => { set.delete(listener); }; } - off(event: K, listener: Listener): this { + off(event: K, listener: Listener): void { this.listeners.get(event as string)?.delete(listener); - return this; } - once(event: K, listener: Listener): this { + once(event: K, listener: Listener): () => void { const wrapper = (payload: WebSocketEventMap[K]) => { this.off(event, wrapper); listener(payload); @@ -79,142 +90,106 @@ export class StructWebSocket { return this.on(event, wrapper); } - subscribeMarket(conditionId: string): void { - if (this.activeMarkets.has(conditionId)) return; - this.activeMarkets.add(conditionId); - const msg = this.marketSubscribeMessage(conditionId); - this.transport.addReplayMessage(msg); - this.transport.send(msg); - } - - unsubscribeMarket(conditionId: string): void { - if (!this.activeMarkets.has(conditionId)) return; - this.activeMarkets.delete(conditionId); - const msg: WebSocketMessage = { - type: "unsubscribe_market", - room_id: `market_${conditionId}`, - message: {}, - }; - this.transport.removeReplayMessages( - (m) => m.type === "subscribe_market" && m.room_id === `market_${conditionId}`, - ); - this.transport.send(msg); - } - - subscribeMarketByPosition(positionId: string): void { - if (this.activeMarketPositions.has(positionId)) return; - this.activeMarketPositions.add(positionId); - const msg = this.marketPositionSubscribeMessage(positionId); - this.transport.addReplayMessage(msg); - this.transport.send(msg); - } - - unsubscribeMarketByPosition(positionId: string): void { - if (!this.activeMarketPositions.has(positionId)) return; - this.activeMarketPositions.delete(positionId); - const msg: WebSocketMessage = { - type: "unsubscribe_market", - room_id: `market_position_${positionId}`, - message: {}, - }; - this.transport.removeReplayMessages( - (m) => m.type === "subscribe_market" && m.room_id === `market_position_${positionId}`, - ); - this.transport.send(msg); - } - - trackWallets(addresses: Address[]): void { - const uniqueAddresses = [...new Set(addresses)]; - const added = uniqueAddresses.filter((addr) => !this.activeWallets.has(addr)); - if (added.length === 0) return; - for (const addr of added) this.activeWallets.add(addr); - const msg = this.walletTrackMessage("subscribe", added); - this.rebuildWalletReplay(); - this.transport.send(msg); - } - - untrackWallets(addresses: Address[]): void { - const uniqueAddresses = [...new Set(addresses)]; - const removed = uniqueAddresses.filter((addr) => this.activeWallets.has(addr)); - if (removed.length === 0) return; - for (const addr of removed) this.activeWallets.delete(addr); - const msg = this.walletTrackMessage("unsubscribe", removed); - this.rebuildWalletReplay(); - this.transport.send(msg); - } - - subscribeWhaleTrades(): void { - this.subscribeSpecialRoom("whale_trades"); + removeAllListeners(event?: keyof WebSocketEventMap): void { + if (event) { + this.listeners.delete(event as string); + } else { + this.listeners.clear(); + } } - unsubscribeWhaleTrades(): void { - this.unsubscribeSpecialRoom("whale_trades"); - } + subscribe(room: R, filters?: WsSubscriptionMap[R]): Promise; + subscribe(room: R, filters: WsSubscriptionMap[R]): Promise; + subscribe(room: R, filters?: WsSubscriptionMap[R]): Promise { + const resolvedFilters = (filters ?? {}) as Record; + const isNewRoom = !this.subscriptions.has(room); + this.subscriptions.set(room, resolvedFilters); + this.rebuildReplay(); - subscribeSmartMoneyTrades(): void { - this.subscribeSpecialRoom("smart_money_trades"); - } + if (isNewRoom) { + this.transport.send({ type: "join_room", payload: { room_id: room } }); + } + this.transport.send({ + type: "room_message", + payload: { room_id: room, message: { action: "subscribe", ...resolvedFilters } }, + }); + + const existing = this.pendingSubscribes.get(room); + if (existing) { + clearTimeout(existing.timer); + existing.reject(new WebSocketError("Superseded by new subscription")); + } - unsubscribeSmartMoneyTrades(): void { - this.unsubscribeSpecialRoom("smart_money_trades"); - } + return new Promise((resolve, reject) => { + const timer = setTimeout(() => { + this.pendingSubscribes.delete(room); + reject(new WebSocketError(`Subscribe to ${room} timed out`)); + }, this.subscribeTimeout); - subscribeInsiderTrades(): void { - this.subscribeSpecialRoom("insider_trades"); + this.pendingSubscribes.set(room, { + resolve: resolve as (data: unknown) => void, + reject, + timer, + }); + }); } - unsubscribeInsiderTrades(): void { - this.unsubscribeSpecialRoom("insider_trades"); - } + unsubscribe(room: WsRoomId): void { + if (!this.subscriptions.has(room)) return; - trackConditions(conditionIds: string[]): void { - const uniqueConditionIds = [...new Set(conditionIds)]; - const added = uniqueConditionIds.filter((id) => !this.activeConditions.has(id)); - if (added.length === 0) return; - for (const id of added) this.activeConditions.add(id); - const msg = this.conditionsTrackMessage("subscribe", added); - this.rebuildConditionsReplay(); - this.transport.send(msg); - } + const pending = this.pendingSubscribes.get(room); + if (pending) { + clearTimeout(pending.timer); + pending.reject(new WebSocketError("Unsubscribed")); + this.pendingSubscribes.delete(room); + } - untrackConditions(conditionIds: string[]): void { - const uniqueConditionIds = [...new Set(conditionIds)]; - const removed = uniqueConditionIds.filter((id) => this.activeConditions.has(id)); - if (removed.length === 0) return; - for (const id of removed) this.activeConditions.delete(id); - const msg = this.conditionsTrackMessage("unsubscribe", removed); - this.rebuildConditionsReplay(); - this.transport.send(msg); + this.transport.send({ + type: "room_message", + payload: { room_id: room, message: { action: "unsubscribe_all" } }, + }); + this.transport.send({ type: "leave_room", payload: { room_id: room } }); + this.subscriptions.delete(room); + this.rebuildReplay(); + } + + private rebuildReplay(): void { + this.transport.clearReplayMessages(); + for (const [roomId, filters] of this.subscriptions) { + this.transport.addReplayMessage({ type: "join_room", payload: { room_id: roomId } }); + this.transport.addReplayMessage({ + type: "room_message", + payload: { room_id: roomId, message: { action: "subscribe", ...filters } }, + }); + } } private handleOpen(): void { + this.startPing(); this.emit("connected", undefined as never); } private handleClose(code: number, reason: string): void { + this.stopPing(); this.emit("disconnected", { code, reason }); } private handleMessage(raw: unknown): void { - const msg = raw as WebSocketServerMessage; - if (!msg || typeof msg !== "object") return; - - const roomId = msg.room_id ?? ""; - const type = msg.type; - - if (type === "market_trade" || roomId.startsWith("market_")) { - this.emit("market_trade", msg.data as never); - } else if (type === "whale_trade" || roomId === "whale_trades") { - this.emit("whale_trade", msg.data as never); - } else if (type === "smart_money_trade" || roomId === "smart_money_trades") { - this.emit("smart_money_trade", msg.data as never); - } else if (type === "insider_trade" || roomId === "insider_trades") { - this.emit("insider_trade", msg.data as never); - } else if (type === "wallet_tracking_alert") { - this.emit("wallet_tracking_alert", msg.data as never); - } else if (type === "conditions_tracking_alert") { - this.emit("conditions_tracking_alert", msg.data as never); + const msg = raw as { type?: string; room_id?: string; data?: unknown }; + if (!msg || typeof msg !== "object" || !msg.type) return; + if (msg.type === "pong") return; + + if (msg.type === "subscribed" && msg.room_id) { + const pending = this.pendingSubscribes.get(msg.room_id as WsRoomId); + if (pending) { + clearTimeout(pending.timer); + this.pendingSubscribes.delete(msg.room_id as WsRoomId); + pending.resolve(msg.data); + } + return; } + + this.emit(msg.type as keyof WebSocketEventMap, msg.data as never); } private emit(event: K, payload: WebSocketEventMap[K]): void { @@ -227,55 +202,17 @@ export class StructWebSocket { } } - private marketSubscribeMessage(conditionId: string): WebSocketMessage { - return { type: "subscribe_market", room_id: `market_${conditionId}`, message: {} }; - } - - private marketPositionSubscribeMessage(positionId: string): WebSocketMessage { - return { type: "subscribe_market", room_id: `market_position_${positionId}`, message: {} }; - } - - private walletTrackMessage(action: string, addresses: Address[]): WebSocketMessage { - return { type: "wallet_tracking", action, wallet_addresses: addresses }; - } - - private conditionsTrackMessage(action: string, conditionIds: string[]): WebSocketMessage { - return { type: "conditions_tracking", action, condition_ids: conditionIds }; - } - - private subscribeSpecialRoom(roomId: string): void { - if (this.activeSpecialRooms.has(roomId)) return; - this.activeSpecialRooms.add(roomId); - const msg: WebSocketMessage = { type: "subscribe_market", room_id: roomId, message: {} }; - this.transport.addReplayMessage(msg); - this.transport.send(msg); - } - - private unsubscribeSpecialRoom(roomId: string): void { - if (!this.activeSpecialRooms.has(roomId)) return; - this.activeSpecialRooms.delete(roomId); - const msg: WebSocketMessage = { type: "unsubscribe_market", room_id: roomId, message: {} }; - this.transport.removeReplayMessages( - (m) => m.type === "subscribe_market" && m.room_id === roomId, - ); - this.transport.send(msg); - } - - private rebuildWalletReplay(): void { - this.transport.removeReplayMessages((m) => m.type === "wallet_tracking"); - if (this.activeWallets.size > 0) { - this.transport.addReplayMessage( - this.walletTrackMessage("subscribe", [...this.activeWallets]), - ); - } + private startPing(): void { + this.stopPing(); + this.pingTimer = setInterval(() => { + this.transport.send({ type: "ping" }); + }, PING_INTERVAL_MS); } - private rebuildConditionsReplay(): void { - this.transport.removeReplayMessages((m) => m.type === "conditions_tracking"); - if (this.activeConditions.size > 0) { - this.transport.addReplayMessage( - this.conditionsTrackMessage("subscribe", [...this.activeConditions]), - ); + private stopPing(): void { + if (this.pingTimer !== null) { + clearInterval(this.pingTimer); + this.pingTimer = null; } } } From 6c8fb78be7a5539e0107b23d0d788ddd890e338a Mon Sep 17 00:00:00 2001 From: elliotdotsol Date: Wed, 18 Mar 2026 18:09:41 +0700 Subject: [PATCH 04/12] update: gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 6fd243c..3705285 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ dist/ *.tsbuildinfo .DS_Store .env -logs/ \ No newline at end of file +logs/ +*.tgz \ No newline at end of file From 3a301983b047d3c28efe3e37bb6413684aa98002 Mon Sep 17 00:00:00 2001 From: elliotdotsol Date: Thu, 19 Mar 2026 21:03:05 +0700 Subject: [PATCH 05/12] update: types --- openapi/ws.json | 2 +- src/ws.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openapi/ws.json b/openapi/ws.json index 34199ee..c54db54 100644 --- a/openapi/ws.json +++ b/openapi/ws.json @@ -3,7 +3,7 @@ "info": { "title": "Polymarket WebSocket API", "version": "1.0.0", - "description": "Real-time WebSocket streaming API for Polymarket prediction-market data.\n\n## Connection\nConnect to `wss://api.struct.to/ws` using a standard WebSocket client.\n\n## Authentication\nAfter connecting, send:\n```json\n{\"type\":\"authenticate\",\"jwt\":\"\"}\n```\nUnauthenticated connections can read public rooms but credit checks are enforced.\n\n## Joining a room\n```json\n{\"type\":\"join_room\",\"payload\":{\"room_id\":\"polymarket_trades\"}}\n```\n\n## Subscribing\nAfter joining, send a `room_message` with room-specific subscribe payload:\n```json\n{\n\"type\": \"room_message\",\n\"payload\": {\n\"room_id\": \"polymarket_trades\",\n\"message\": {\"action\":\"subscribe\",\"condition_ids\":[\"0xabc…\"]}\n}\n}\n```\n\n## Keepalive\nThe server expects a `{\"type\":\"ping\"}` or WebSocket ping frame at least every 60 seconds." + "description": "Real-time WebSocket streaming API for Polymarket prediction-market data.\n\n## Connection\nConnect to `wss://api.struct.to/ws` using a standard WebSocket client.\n\n## Authentication\nAn API key is required. Pass it via **header** or **query parameter**:\n\n**Header (recommended):**\n```\nX-Api-Key: \n```\n\n**Query parameter (browser / frontend):**\n```\nwss://api.struct.to/ws?api_key=\n```\n\nThe query parameter is only used when no `X-Api-Key` header is present.\n\n## Joining a room\nAfter connecting, send:\n```json\n{\"type\":\"join_room\",\"payload\":{\"room_id\":\"polymarket_trades\"}}\n```\n\n## Subscribing\nAfter joining, send a `room_message` with room-specific subscribe payload:\n```json\n{\n\"type\": \"room_message\",\n\"payload\": {\n\"room_id\": \"polymarket_trades\",\n\"message\": {\"action\":\"subscribe\",\"condition_ids\":[\"0xabc…\"]}\n}\n}\n```\n\n## Keepalive\nThe server sends a `ping` text frame every **30 seconds**. Respond with a `pong` text frame to stay connected. Connections that do not respond within **60 seconds** (two missed pings) are closed." }, "servers": { "production": { diff --git a/src/ws.ts b/src/ws.ts index e73aa4f..75f0c2f 100644 --- a/src/ws.ts +++ b/src/ws.ts @@ -34,7 +34,7 @@ export class StructWebSocket { constructor(config: StructWebSocketConfig) { this.subscribeTimeout = config.subscribeTimeout ?? DEFAULT_SUBSCRIBE_TIMEOUT_MS; const wsUrl = (config.wsUrl ?? DEFAULT_WS_URL).replace(/\/+$/, ""); - const url = `${wsUrl}?token=${encodeURIComponent(config.apiKey)}`; + const url = `${wsUrl}?api-key=${encodeURIComponent(config.apiKey)}`; this.transport = new WebSocketTransport( url, From 46f438cf1ff05fa244186e56d9607a31fb1c1bac Mon Sep 17 00:00:00 2001 From: elliotdotsol Date: Tue, 31 Mar 2026 01:21:57 +0700 Subject: [PATCH 06/12] update: ws --- openapi/polymarket.json | 2 +- openapi/webhooks.json | 14 ----------- openapi/ws.json | 50 +++++++++++++++++++++++++++++++++++++ src/generated/polymarket.ts | 14 ++++------- src/generated/webhooks.ts | 4 --- src/types/index.ts | 3 +++ src/types/ws.ts | 16 ++++++++++++ 7 files changed, 75 insertions(+), 28 deletions(-) diff --git a/openapi/polymarket.json b/openapi/polymarket.json index ac20cfd..cca6ace 100644 --- a/openapi/polymarket.json +++ b/openapi/polymarket.json @@ -1 +1 @@ -{"openapi":"3.1.0","info":{"title":"Polymarket API","description":"RESTful API for querying Polymarket prediction markets data including events, markets, traders, holders, and real-time metrics","license":{"name":""},"version":"1.0.0"},"servers":[{"url":"https://api.struct.to/v1","description":"Production"}],"paths":{"/polymarket/asset-history":{"get":{"tags":["Assets"],"summary":"Get Asset Price History","description":"Returns historical price data for supported crypto assets from Polymarket API","operationId":"get_asset_history","parameters":[{"name":"asset_symbol","in":"query","description":"Asset ticker: BTC, ETH, XRP, SOL, DOGE, BNB, HYPE","required":true,"schema":{"type":"string"},"example":"BTC"},{"name":"variant","in":"query","description":"Time window: 5m, 15m, 1h, 4h, 1d","required":true,"schema":{"type":"string"},"example":"1h"},{"name":"from","in":"query","description":"Start timestamp in seconds (Unix epoch, inclusive)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp in seconds (Unix epoch, inclusive)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"limit","in":"query","description":"Number of results (default: 10, max: 100)","required":false,"schema":{"type":"integer","format":"int64"},"example":10}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AssetPriceHistoryRow"}}}}},"400":{"description":"Bad request - missing or invalid parameters"},"500":{"description":"Internal server error"}}}},"/polymarket/events":{"get":{"tags":["Events"],"summary":"Get events","description":"Retrieve a paginated list of events with filtering, sorting, and optional nested tags/markets","operationId":"get_events","parameters":[{"name":"id","in":"query","description":"Filter by event ID(s) - comma-separated (max 50). Cannot be used with 'event_slugs'. Example: id=99600,99601,99583","required":false,"schema":{"type":"string"}},{"name":"event_slugs","in":"query","description":"Filter by event slug(s) - comma-separated (max 50). Cannot be used with 'id'. Example: event_slugs=will-trump-win,bitcoin-100k","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","description":"Search in title and description (3-100 characters). Example: search=trump","required":false,"schema":{"type":"string"}},{"name":"sort_by","in":"query","description":"Sort: volume, txns, unique_traders, title, creation_date, start_date, end_date, relevance (relevance only works in search mode) (default: volume)","required":false,"schema":{"$ref":"#/components/schemas/EventSortBy"}},{"name":"sort_dir","in":"query","description":"Sort direction: asc, desc (default: desc)","required":false,"schema":{"$ref":"#/components/schemas/SortDirection"}},{"name":"timeframe","in":"query","description":"Metrics timeframe: 1m, 5m, 30m, 1h, 6h, 24h, 7d, 30d (default: 24h)","required":false,"schema":{"$ref":"#/components/schemas/MetricsTimeframe"}},{"name":"status","in":"query","description":"Filter by status: open, closed, or all (default: all)","required":false,"schema":{"$ref":"#/components/schemas/MarketStatus"}},{"name":"categories","in":"query","description":"Comma-separated category filters","required":false,"schema":{"type":"string"}},{"name":"exclude_categories","in":"query","description":"Comma-separated categories to exclude","required":false,"schema":{"type":"string"}},{"name":"tags","in":"query","description":"Filter by tag slug(s) - comma-separated (max 50). Example: tags=sports,football,crypto","required":false,"schema":{"type":"string"}},{"name":"exclude_tags","in":"query","description":"Comma-separated tag slugs to exclude","required":false,"schema":{"type":"string"}},{"name":"min_volume","in":"query","description":"Minimum volume in selected timeframe","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_volume","in":"query","description":"Maximum volume in selected timeframe","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_txns","in":"query","description":"Minimum transactions in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"max_txns","in":"query","description":"Maximum transactions in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"min_unique_traders","in":"query","description":"Minimum unique traders in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"max_unique_traders","in":"query","description":"Maximum unique traders in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"include_tags","in":"query","description":"Include tags array (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_markets","in":"query","description":"Include markets array with outcomes (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_metrics","in":"query","description":"Include metrics object with all timeframes (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key","required":false,"schema":{"type":"string"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of Polymarket events with nested tags, markets, and series. Response includes `pagination: { has_more, pagination_key }` for cursor-based pagination.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PolymarketEvent"}}}}},"400":{"description":"Bad request - validation error (search length, array limits, conflicting params)"}}}},"/polymarket/events/chart":{"get":{"tags":["Events"],"summary":"Get event chart","description":"Retrieve price data over time for up to 4 markets with highest YES outcome (outcome_index 0) prices in an event. Perfect for rendering multi-line charts showing price movement across top markets. TradingView-style: resolution parameter determines both candle size and implicit lookback period.","operationId":"get_event_chart","parameters":[{"name":"event_slug","in":"query","description":"Event slug (required)","required":true,"schema":{"type":"string"}},{"name":"condition_ids","in":"query","description":"Comma-separated condition IDs to include (max 4, optional)","required":false,"schema":{"type":"string"}},{"name":"market_slugs","in":"query","description":"Comma-separated market slugs to include (max 4, optional). Use either condition_ids or market_slugs, not both","required":false,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Time interval with implicit lookback: 1H (1 hour), 6H (6 hours), 1D (1 day), 1W (1 week), 1M (30 days), ALL (all data) (required)","required":true,"schema":{"type":"string","enum":["1H","6H","1D","1W","1M","ALL"]}}],"responses":{"200":{"description":"Price data over time for up to 4 markets with highest YES odds","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventMarketChartOutcome"}}}}}}}},"/polymarket/events/metrics":{"get":{"tags":["Events"],"summary":"Get event metrics","description":"Retrieve volume, transaction, and trader metrics for an event. Supports single timeframe (e.g., '1m'), multiple timeframes (e.g., '1m,5m,1h'), or 'all' to get all available timeframes.","operationId":"get_event_metrics","parameters":[{"name":"event_slug","in":"query","description":"Event slug","required":true,"schema":{"type":"string"}},{"name":"timeframe","in":"query","description":"Timeframe: single (1m, 5m, 30m, 1h, 6h, 24h, 7d, 30d), comma-separated (1m,5m,1h), or 'all'","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Event metrics for the specified timeframe(s). Returns single object for one timeframe, array for multiple.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventMetricsResponse"}}}},"400":{"description":"Invalid timeframe"}}}},"/polymarket/events/outcomes":{"get":{"tags":["Events"],"summary":"Get event market outcomes","description":"Returns the winning outcome name for each resolved market in an event, keyed by market slug. Useful for quickly checking which outcomes won across a series.","operationId":"get_event_outcomes","parameters":[{"name":"event_slug","in":"query","description":"Event slug (required)","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Number of resolved markets per page (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key for fetching next page","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Map of market_slug → winning outcome name with pagination metadata","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}}}}},"400":{"description":"Missing event_slug parameter"}}}},"/polymarket/events/slug/{slug}":{"get":{"tags":["Events"],"summary":"Get event by slug","description":"Retrieve a single event by its slug with optional nested tags, markets, and metrics","operationId":"get_event_by_slug","parameters":[{"name":"slug","in":"path","description":"Event slug","required":true,"schema":{"type":"string"}},{"name":"include_tags","in":"query","description":"Include tags array (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_markets","in":"query","description":"Include markets array with outcomes (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_metrics","in":"query","description":"Include metrics object with all timeframes (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Event with nested tags, markets, and series","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PolymarketEvent"}}}},"404":{"description":"Event not found"}}}},"/polymarket/events/{identifier}":{"get":{"tags":["Events"],"summary":"Get event by ID or slug","description":"Retrieve a single event by its numeric ID or slug with optional nested tags, markets, and metrics","operationId":"get_event","parameters":[{"name":"identifier","in":"path","description":"Event ID or slug","required":true,"schema":{"type":"string"}},{"name":"include_tags","in":"query","description":"Include tags array (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_markets","in":"query","description":"Include markets array with outcomes (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_metrics","in":"query","description":"Include metrics object with all timeframes (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Event with nested tags, markets, and series","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PolymarketEvent"}}}},"404":{"description":"Event not found"}}}},"/polymarket/holders/markets":{"get":{"tags":["Holders"],"summary":"Get market holders","description":"Retrieve holders of a market grouped by outcome, sorted by shares held. Identify the market with either `condition_id` or `market_slug` — exactly one must be provided. Set `include_pnl=true` to include a nested holder `pnl` object.","operationId":"get_market_holders","parameters":[{"name":"condition_id","in":"query","description":"Market condition ID (0x-prefixed hex)","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (e.g. `will-trump-win`)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"min_shares","in":"query","description":"Minimum shares held (decimal string)","required":false,"schema":{"type":"string"}},{"name":"max_shares","in":"query","description":"Maximum shares held (decimal string)","required":false,"schema":{"type":"string"}},{"name":"include_pnl","in":"query","description":"Include nested holder PnL data (default: false, +1 credit)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Market holders grouped by outcome (sorted by shares DESC). Holder `pnl` is included only when `include_pnl=true`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarketHoldersResponse"}}}},"404":{"description":"Market not found"}}}},"/polymarket/holders/markets/history":{"get":{"tags":["Holders"],"summary":"Get market holders history","description":"Retrieve historical holder count snapshots for a market over a time range. Identify the market with either `condition_id` or `market_slug` — exactly one must be provided.","operationId":"get_market_holders_history","parameters":[{"name":"condition_id","in":"query","description":"Market condition ID (0x-prefixed hex)","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (e.g. `will-trump-win`)","required":false,"schema":{"type":"string"}},{"name":"hours","in":"query","description":"Time range in hours (default: 24, max: 336 = 14 days)","required":false,"schema":{"type":"number","format":"double"}}],"responses":{"200":{"description":"Market holder count history with automatic granularity (1m/5m/15m/1h/6h buckets)","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/HolderHistoryCandle"}}}}},"404":{"description":"Market not found"}}}},"/polymarket/holders/positions/{position_id}":{"get":{"tags":["Holders"],"summary":"Get position holders","description":"Retrieve holders of a specific position (ERC1155 token), sorted by shares held. Set `include_pnl=true` to include nested holder PnL. Uses cursor-based pagination for efficient traversal.","operationId":"get_position_holders","parameters":[{"name":"position_id","in":"path","description":"Position ID (ERC1155 token ID)","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key","required":false,"schema":{"type":"string"}},{"name":"min_shares","in":"query","description":"Minimum shares held (decimal string)","required":false,"schema":{"type":"string"}},{"name":"max_shares","in":"query","description":"Maximum shares held (decimal string)","required":false,"schema":{"type":"string"}},{"name":"include_pnl","in":"query","description":"Include nested holder PnL data (default: false, +1 credit)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Position holders (sorted by shares DESC). Holder `pnl` is included only when `include_pnl=true`. Response includes `pagination: { has_more, pagination_key }` for cursor-based pagination.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PositionHoldersResponse"}}}},"404":{"description":"Position not found"}}}},"/polymarket/holders/positions/{position_id}/history":{"get":{"tags":["Holders"],"summary":"Get position holders history","description":"Retrieve historical holder count snapshots for a position over a time range","operationId":"get_position_holders_history","parameters":[{"name":"position_id","in":"path","description":"Position ID (ERC1155 token ID)","required":true,"schema":{"type":"string"}},{"name":"hours","in":"query","description":"Time range in hours (default: 24, max: 336 = 14 days)","required":false,"schema":{"type":"number","format":"double"}}],"responses":{"200":{"description":"Position holder count history with automatic granularity (1m/5m/15m/1h/6h buckets)","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/HolderHistoryCandle"}}}}},"404":{"description":"Position not found"}}}},"/polymarket/market":{"get":{"tags":["Market"],"summary":"Get markets","description":"Retrieve a paginated list of markets with filtering, sorting, and optional nested tags/events/metrics","operationId":"list_markets","parameters":[{"name":"condition_ids","in":"query","description":"Filter by condition ID(s) - comma-separated (max 50)","required":false,"schema":{"type":"string"}},{"name":"question_ids","in":"query","description":"Filter by question ID(s) - comma-separated (max 50)","required":false,"schema":{"type":"string"}},{"name":"market_ids","in":"query","description":"Filter by market ID(s) - comma-separated (max 50)","required":false,"schema":{"type":"string"}},{"name":"market_slugs","in":"query","description":"Filter by market slug(s) - comma-separated (max 50)","required":false,"schema":{"type":"string"}},{"name":"event_slugs","in":"query","description":"Filter by event slug(s) - comma-separated (max 50)","required":false,"schema":{"type":"string"}},{"name":"position_ids","in":"query","description":"Filter by position ID(s) - comma-separated (max 50)","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","description":"Search in title (3-100 characters)","required":false,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Filter by status: open, closed, or all (default: all)","required":false,"schema":{"$ref":"#/components/schemas/MarketStatus"}},{"name":"sort_by","in":"query","description":"Sort: volume, txns, unique_traders, liquidity, holders, end_time, start_time, created_time, relevance","required":false,"schema":{"$ref":"#/components/schemas/MarketSortBy"}},{"name":"sort_dir","in":"query","description":"Sort direction: asc, desc (default: desc)","required":false,"schema":{"$ref":"#/components/schemas/SortDirection"}},{"name":"timeframe","in":"query","description":"Metrics timeframe: 1m, 5m, 30m, 1h, 6h, 24h, 7d, 30d (default: 24h)","required":false,"schema":{"$ref":"#/components/schemas/MetricsTimeframe"}},{"name":"min_volume","in":"query","description":"Minimum total volume USD","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_volume","in":"query","description":"Maximum total volume USD","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_liquidity","in":"query","description":"Minimum liquidity USD","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_liquidity","in":"query","description":"Maximum liquidity USD","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_txns","in":"query","description":"Minimum transactions in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"max_txns","in":"query","description":"Maximum transactions in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"min_unique_traders","in":"query","description":"Minimum unique traders in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"max_unique_traders","in":"query","description":"Maximum unique traders in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"min_holders","in":"query","description":"Minimum total holders","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"max_holders","in":"query","description":"Maximum total holders","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"categories","in":"query","description":"Comma-separated category filters (max 50)","required":false,"schema":{"type":"string"}},{"name":"exclude_categories","in":"query","description":"Comma-separated categories to exclude","required":false,"schema":{"type":"string"}},{"name":"tags","in":"query","description":"Filter by tag(s) - comma-separated (max 50)","required":false,"schema":{"type":"string"}},{"name":"exclude_tags","in":"query","description":"Comma-separated tags to exclude","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Filter markets with end_time >= start_time (Unix timestamp)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"end_time","in":"query","description":"Filter markets with end_time <= end_time (Unix timestamp)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"include_tags","in":"query","description":"Include tags array (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_event","in":"query","description":"Include event object (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_metrics","in":"query","description":"Include all timeframe metrics (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key","required":false,"schema":{"type":"string"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of markets with metadata, outcomes, tags, event, and metrics. Response includes `pagination: { has_more, pagination_key }` for cursor-based pagination.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MarketResponse"}}}}},"400":{"description":"Bad request - validation error (search length, array limits, conflicting params)"}}}},"/polymarket/market/bonds":{"get":{"tags":["Bonds"],"summary":"Get bonds","description":"Retrieve a list of bond markets sorted by yield, filtered by probability and time to expiry","operationId":"get_bonds","parameters":[{"name":"min_probability","in":"query","description":"Minimum probability threshold (default: 0.85)","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_hours","in":"query","description":"Maximum hours until market end","required":false,"schema":{"type":"number","format":"double"}},{"name":"limit","in":"query","description":"Number of results (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor for pagination: end_date (unix epoch) of the last item from the previous page","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"List of bond markets sorted by yield","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BondMarket"}}}}}}}},"/polymarket/market/candlestick":{"get":{"tags":["Market"],"summary":"Get market candlesticks by condition_id","description":"Retrieve OHLCV candlestick data for a market by its condition_id","operationId":"get_market_candlestick","parameters":[{"name":"condition_id","in":"query","description":"Market condition ID (required)","required":true,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Candle interval: 1, 5, 15, 30, 60, 240, D, 1D","required":true,"schema":{"$ref":"#/components/schemas/CandlestickResolution"}},{"name":"count_back","in":"query","description":"Number of candles (max: 2500)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"from","in":"query","description":"Start timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"OHLCV candlestick data","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PredictionCandlestickBar"}}}}}}}},"/polymarket/market/chart":{"get":{"tags":["Market"],"summary":"Get market chart","description":"Retrieve price data over time for up to 4 position outcomes in a market condition. TradingView-style: resolution parameter determines both candle size and implicit lookback period. Auto-selects the 4 most active outcomes if position_ids not specified.","operationId":"get_chart","parameters":[{"name":"condition_id","in":"query","description":"Market condition ID or market_slug (one required)","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (alternative to condition_id)","required":false,"schema":{"type":"string"}},{"name":"position_ids","in":"query","description":"Comma-separated list of position IDs (max 4, optional). Auto-selected if not provided","required":false,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Time interval with implicit lookback: 1H (1 hour), 6H (6 hours), 1D (1 day), 1W (1 week), 1M (30 days), ALL (all data) (required)","required":true,"schema":{"type":"string","enum":["1H","6H","1D","1W","1M","ALL"]}}],"responses":{"200":{"description":"Price data over time for up to 4 market outcomes","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PositionChartOutcome"}}}}}}}},"/polymarket/market/metrics":{"get":{"tags":["Market"],"summary":"Get market metrics","description":"Retrieve volume, transaction, and trader metrics for a market. Supports single timeframe (e.g., '1m'), multiple timeframes (e.g., '1m,5m,1h'), or 'all' to get all available timeframes.","operationId":"get_market_metrics","parameters":[{"name":"condition_id","in":"query","description":"Market condition ID","required":true,"schema":{"type":"string"}},{"name":"timeframe","in":"query","description":"Timeframe: single (1m, 5m, 30m, 1h, 6h, 24h, 7d, 30d), comma-separated (1m,5m,1h), or 'all'","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Market metrics for the specified timeframe(s). Returns single object for one timeframe, array for multiple.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConditionMetricsResponse"}}}},"400":{"description":"Invalid timeframe"}}}},"/polymarket/market/position/candlestick":{"get":{"tags":["Market"],"summary":"Get position candlesticks by position_id","description":"Retrieve OHLCV candlestick data for a specific position by its position_id","operationId":"get_position_candlestick","parameters":[{"name":"position_id","in":"query","description":"Position/token ID (required)","required":true,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Candle interval: 1, 5, 15, 30, 60, 240, D, 1D","required":true,"schema":{"$ref":"#/components/schemas/CandlestickResolution"}},{"name":"count_back","in":"query","description":"Number of candles (max: 2500)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"from","in":"query","description":"Start timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"OHLCV candlestick data","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PredictionCandlestickBar"}}}}}}}},"/polymarket/market/position/metrics":{"get":{"tags":["Market"],"summary":"Get position metrics","description":"Retrieve volume, transaction, and trader metrics for a specific position. Supports single timeframe (e.g., '1m'), multiple timeframes (e.g., '1m,5m,1h'), or 'all' to get all available timeframes.","operationId":"get_position_metrics","parameters":[{"name":"position_id","in":"query","description":"Position/token ID","required":true,"schema":{"type":"string"}},{"name":"timeframe","in":"query","description":"Timeframe: single (1m, 5m, 30m, 1h, 6h, 24h, 7d, 30d), comma-separated (1m,5m,1h), or 'all'","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Position metrics for the specified timeframe(s). Returns single object for one timeframe, array for multiple.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PositionMetricsResponse"}}}},"400":{"description":"Invalid timeframe"}}}},"/polymarket/market/position/volume-chart":{"get":{"tags":["Market"],"summary":"Get position volume chart","description":"Retrieve volume over time for a specific position with buy/sell breakdown","operationId":"get_position_volume_chart","parameters":[{"name":"position_id","in":"query","description":"Position/token ID (required)","required":true,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Time interval: 1, 5, 15, 30, 60, 240, D, 1D (default: 60)","required":false,"schema":{"$ref":"#/components/schemas/CandlestickResolution"}},{"name":"count_back","in":"query","description":"Number of data points (max: 2500)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"from","in":"query","description":"Start timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Volume with buy/sell breakdown over time","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PositionVolumeDataPoint"}}}}}}}},"/polymarket/market/price-jumps":{"get":{"tags":["Market"],"summary":"Detect price jumps","description":"Scan candles for significant price movements. Returns jumps with from/to timestamps in milliseconds, directly usable as trades API time range parameters to identify traders who traded before or during the movement.","operationId":"get_price_jumps","parameters":[{"name":"condition_id","in":"query","description":"Market condition ID (one of condition_id or market_slug required)","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (resolved to condition_id)","required":false,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Candle resolution in minutes: 1, 5, 15, 30, 60, 240 (default: 15)","required":false,"schema":{"type":"string"}},{"name":"min_change_pct","in":"query","description":"Minimum relative percent change to qualify as a jump (default: 10.0)","required":false,"schema":{"type":"number","format":"double"}},{"name":"lookback","in":"query","description":"Number of candles to scan back from now (default: 1440, max: 2500)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"offset","in":"query","description":"Offset in candles from now — window is [now - (lookback + offset) * resolution, now - offset * resolution] (default: 0)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Price jumps sorted by timestamp descending","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PriceJump"}}}}}}}},"/polymarket/market/slug/{slug}":{"get":{"tags":["Market"],"summary":"Get market by slug","description":"Retrieve a single market by its slug with optional nested tags, event, and metrics","operationId":"get_market_by_slug","parameters":[{"name":"slug","in":"path","description":"Market slug (e.g. `will-trump-win`)","required":true,"schema":{"type":"string"}},{"name":"include_tags","in":"query","description":"Include tags array (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_event","in":"query","description":"Include event object (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_metrics","in":"query","description":"Include all timeframe metrics (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Market with metadata, outcomes, tags, event, and metrics","content":{"application/json":{"schema":{"type":"object","description":"Formatted market response with structured metrics, tags, outcomes, and event","required":["condition_id","status"],"properties":{"condition_id":{"type":"string"},"id":{"type":["string","null"]},"market_slug":{"type":["string","null"]},"question":{"type":["string","null"]},"title":{"type":["string","null"]},"description":{"type":["string","null"]},"image_url":{"type":["string","null"]},"oracle":{"type":["string","null"]},"status":{"type":"string"},"created_time":{"type":["integer","null"],"format":"int64"},"start_time":{"type":["integer","null"],"format":"int64"},"game_start_time":{"type":["integer","null"],"format":"int64"},"closed_time":{"type":["integer","null"],"format":"int64"},"end_time":{"type":["integer","null"],"format":"int64"},"accepting_orders":{"type":["boolean","null"]},"uma_resolution_status":{"type":["string","null"]},"is_neg_risk":{"type":["boolean","null"]},"market_maker_address":{"type":["string","null"]},"creator":{"type":["string","null"]},"category":{"type":["string","null"]},"volume_usd":{"type":["number","null"],"format":"double"},"liquidity_usd":{"type":["number","null"],"format":"double"},"highest_probability":{"type":["number","null"],"format":"double"},"total_holders":{"type":["integer","null"],"format":"int64"},"winning_outcome":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/MarketOutcome"}]},"outcomes":{"type":"array","items":{"$ref":"#/components/schemas/MarketOutcome"}},"rewards":{"type":"array","items":{"$ref":"#/components/schemas/MarketReward"}},"clob_rewards":{"type":"array","items":{"$ref":"#/components/schemas/ClobReward"}},"tags":{"type":"array","items":{"type":"string"}},"event_slug":{"type":["string","null"]},"resolution_source":{"type":["string","null"]},"metrics":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/SimpleTimeframeMetrics"},"propertyNames":{"type":"string"}},"relevance_score":{"type":["number","null"],"format":"double"}}}}}},"404":{"description":"Market not found"}}}},"/polymarket/market/trades":{"get":{"tags":["Market"],"summary":"Get market trades","description":"Retrieve trades for one or more markets, with filtering by trader, side, price, amount, and time range","operationId":"get_market_trades","parameters":[{"name":"condition_ids","in":"query","description":"Comma-separated condition IDs (max 20)","required":false,"schema":{"type":"string"}},{"name":"slugs","in":"query","description":"Comma-separated market slugs","required":false,"schema":{"type":"string"}},{"name":"position_ids","in":"query","description":"Comma-separated position IDs","required":false,"schema":{"type":"string"}},{"name":"traders","in":"query","description":"Comma-separated trader addresses (max 25)","required":false,"schema":{"type":"string"}},{"name":"side","in":"query","description":"Trade side: 0 (Buy), 1 (Sell)","required":false,"schema":{"$ref":"#/components/schemas/TradeSide"}},{"name":"outcome","in":"query","description":"Outcome name filter (e.g. Yes, No)","required":false,"schema":{"type":"string"}},{"name":"outcome_index","in":"query","description":"Outcome index: 0 (Yes), 1 (No)","required":false,"schema":{"$ref":"#/components/schemas/OutcomeIndex"}},{"name":"trade_type","in":"query","description":"Trade type: 0 (OrderFilled), 1 (Redemption), 2 (Merge)","required":false,"schema":{"$ref":"#/components/schemas/TradeType"}},{"name":"min_usd_amount","in":"query","description":"Min USD amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_usd_amount","in":"query","description":"Max USD amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_shares_amount","in":"query","description":"Min shares amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_shares_amount","in":"query","description":"Max shares amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_price","in":"query","description":"Min price (0.0-1.0)","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_price","in":"query","description":"Max price (0.0-1.0)","required":false,"schema":{"type":"number","format":"double"}},{"name":"from","in":"query","description":"Start timestamp (ms)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (ms)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"all","in":"query","description":"Return all-time trades, not just last 30 days (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Results per page (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32","minimum":0}},{"name":"pagination_key","in":"query","description":"Offset-based pagination key (integer offset into result set)","required":false,"schema":{"type":"integer","format":"int32","minimum":0}},{"name":"sort_desc","in":"query","description":"Sort newest first (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Prediction trades matching filters","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PredictionTradeResponse"}}}}}}}},"/polymarket/market/volume-chart":{"get":{"tags":["Market"],"summary":"Get market volume chart","description":"Retrieve volume breakdown by YES/NO outcome over time for a prediction market","operationId":"get_market_volume_chart","parameters":[{"name":"condition_id","in":"query","description":"Market condition ID (or use market_slug)","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (alternative to condition_id)","required":false,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Time interval: 1, 5, 15, 30, 60, 240, D, 1D (default: 60)","required":false,"schema":{"$ref":"#/components/schemas/CandlestickResolution"}},{"name":"count_back","in":"query","description":"Number of data points (max: 2500)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"from","in":"query","description":"Start timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Volume breakdown by YES/NO over time","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MarketVolumeDataPoint"}}}}}}}},"/polymarket/market/{condition_id}":{"get":{"tags":["Market"],"summary":"Get market by condition ID","description":"Retrieve a single market by its condition ID with optional nested tags, event, and metrics","operationId":"get_market","parameters":[{"name":"condition_id","in":"path","description":"Market condition ID (0x-prefixed hex)","required":true,"schema":{"type":"string"}},{"name":"include_tags","in":"query","description":"Include tags array (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_event","in":"query","description":"Include event object (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_metrics","in":"query","description":"Include all timeframe metrics (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Market with metadata, outcomes, tags, event, and metrics","content":{"application/json":{"schema":{"type":"object","description":"Formatted market response with structured metrics, tags, outcomes, and event","required":["condition_id","status"],"properties":{"condition_id":{"type":"string"},"id":{"type":["string","null"]},"market_slug":{"type":["string","null"]},"question":{"type":["string","null"]},"title":{"type":["string","null"]},"description":{"type":["string","null"]},"image_url":{"type":["string","null"]},"oracle":{"type":["string","null"]},"status":{"type":"string"},"created_time":{"type":["integer","null"],"format":"int64"},"start_time":{"type":["integer","null"],"format":"int64"},"game_start_time":{"type":["integer","null"],"format":"int64"},"closed_time":{"type":["integer","null"],"format":"int64"},"end_time":{"type":["integer","null"],"format":"int64"},"accepting_orders":{"type":["boolean","null"]},"uma_resolution_status":{"type":["string","null"]},"is_neg_risk":{"type":["boolean","null"]},"market_maker_address":{"type":["string","null"]},"creator":{"type":["string","null"]},"category":{"type":["string","null"]},"volume_usd":{"type":["number","null"],"format":"double"},"liquidity_usd":{"type":["number","null"],"format":"double"},"highest_probability":{"type":["number","null"],"format":"double"},"total_holders":{"type":["integer","null"],"format":"int64"},"winning_outcome":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/MarketOutcome"}]},"outcomes":{"type":"array","items":{"$ref":"#/components/schemas/MarketOutcome"}},"rewards":{"type":"array","items":{"$ref":"#/components/schemas/MarketReward"}},"clob_rewards":{"type":"array","items":{"$ref":"#/components/schemas/ClobReward"}},"tags":{"type":"array","items":{"type":"string"}},"event_slug":{"type":["string","null"]},"resolution_source":{"type":["string","null"]},"metrics":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/SimpleTimeframeMetrics"},"propertyNames":{"type":"string"}},"relevance_score":{"type":["number","null"],"format":"double"}}}}}},"404":{"description":"Market not found"}}}},"/polymarket/order-book":{"get":{"tags":["Order Book"],"summary":"Get order book","description":"Returns the latest CLOB orderbook snapshot for a position, including derived metrics (best bid/ask, mid price, spread, liquidity depth). Data is sourced from the real-time Polymarket WebSocket feed. `bids` and `asks` are arrays of `{\"p\": price, \"s\": size}` objects, sorted best-first.","operationId":"get_order_book","parameters":[{"name":"position_id","in":"query","description":"Token ID (position ID) to query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Latest orderbook snapshot. ts is Unix milliseconds.","content":{"application/json":{"schema":{"type":"object","required":["ts","position_id","condition_id","bids","asks","hash"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"bids":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"asks":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"hash":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}}}}},"400":{"description":"Missing or invalid parameters"}}}},"/polymarket/order-book/history":{"get":{"tags":["Order Book"],"summary":"Get order book history","description":"Paginated history of raw CLOB orderbook snapshots including full bids/asks levels and derived metrics. Default limit 20, max 200. `bids` and `asks` are arrays of `{\"p\": price, \"s\": size}` objects, sorted best-first.","operationId":"get_order_book_history","parameters":[{"name":"position_id","in":"query","description":"Token ID (required if condition_id / market_slug not set)","required":false,"schema":{"type":"string"}},{"name":"condition_id","in":"query","description":"Condition ID — returns history for all positions in this market","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (alternative to condition_id)","required":false,"schema":{"type":"string"}},{"name":"from","in":"query","description":"Start timestamp (Unix milliseconds, inclusive)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (Unix milliseconds, inclusive)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"min_spread","in":"query","description":"Only return snapshots with spread >= this value","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_spread","in":"query","description":"Only return snapshots with spread <= this value","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_liquidity","in":"query","description":"Only return snapshots where total liquidity (bid + ask) >= this value","required":false,"schema":{"type":"number","format":"double"}},{"name":"limit","in":"query","description":"Number of results (default: 20, max: 200)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"pagination_key","in":"query","description":"Cursor from previous response's pagination.pagination_key","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Orderbook snapshot rows, newest first. ts is Unix milliseconds.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","required":["ts","position_id","condition_id","bids","asks","hash"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"bids":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"asks":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"hash":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}}}}}},"400":{"description":"Missing or invalid parameters"}}}},"/polymarket/order-book/market":{"get":{"tags":["Order Book"],"summary":"Get order books for a market","description":"Returns the latest orderbook snapshot for every position (outcome) in a market. Accepts condition_id or market_slug. `bids` and `asks` are arrays of `{\"p\": price, \"s\": size}` objects, sorted best-first.","operationId":"get_market_order_book","parameters":[{"name":"condition_id","in":"query","description":"Condition ID of the market","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (alternative to condition_id)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Latest orderbook snapshot per position. ts is Unix milliseconds.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","required":["ts","position_id","condition_id","bids","asks","hash"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"bids":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"asks":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"hash":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}}}}}},"400":{"description":"Missing or invalid parameters"}}}},"/polymarket/order-book/spread":{"get":{"tags":["Order Book"],"summary":"Get spread history","description":"Lightweight time series of derived orderbook metrics (best bid/ask, mid price, spread, liquidity depth) without raw bids/asks — ideal for charting. Default limit 20, max 200.","operationId":"get_spread_history","parameters":[{"name":"position_id","in":"query","description":"Token ID (required if condition_id / market_slug not set)","required":false,"schema":{"type":"string"}},{"name":"condition_id","in":"query","description":"Condition ID — returns spread history for all positions in this market","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (alternative to condition_id)","required":false,"schema":{"type":"string"}},{"name":"from","in":"query","description":"Start timestamp (Unix milliseconds, inclusive)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (Unix milliseconds, inclusive)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"min_spread","in":"query","description":"Only return rows with spread >= this value","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_spread","in":"query","description":"Only return rows with spread <= this value","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_liquidity","in":"query","description":"Only return rows where total liquidity (bid + ask) >= this value","required":false,"schema":{"type":"number","format":"double"}},{"name":"limit","in":"query","description":"Number of results (default: 100, max: 1000)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"pagination_key","in":"query","description":"Cursor from previous response's pagination.pagination_key","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Spread time series rows, newest first. ts is Unix milliseconds.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","description":"Lightweight row — derived metrics only, no bids/asks JSONB.","required":["ts","position_id","condition_id"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}}}}}},"400":{"description":"Missing or invalid parameters"}}}},"/polymarket/search":{"get":{"tags":["Search"],"summary":"Search events, markets, and traders","description":"Search across markets, events, and traders. Use `type` to limit which categories are searched. Trader search supports wallet address lookup or name search. Results for each category are independently paginated. Only requested categories are included in the response.","operationId":"search","parameters":[{"name":"q","in":"query","description":"Search query (min 2 characters). Prefix with 0x for exact wallet address lookup.","required":true,"schema":{"type":"string"}},{"name":"type","in":"query","description":"Comma-separated categories to search: events, markets, traders (default: all three, 1 credit per type). Example: type=markets,traders","required":false,"schema":{"type":"string"}},{"name":"include_pnl","in":"query","description":"Include lifetime PnL summary for each trader (default: false, +1 credit)","required":false,"schema":{"type":"boolean"}},{"name":"sort_by","in":"query","description":"Sort field applied to both events and markets (default: volume). Fields marked events-only or markets-only fall back to volume on the other category.","required":false,"schema":{"$ref":"#/components/schemas/SearchSortBy"}},{"name":"sort_dir","in":"query","description":"Sort direction (default: desc)","required":false,"schema":{"$ref":"#/components/schemas/SortDirection"}},{"name":"timeframe","in":"query","description":"Metrics timeframe used for volume/txns/unique_traders sort (default: 24h)","required":false,"schema":{"$ref":"#/components/schemas/MetricsTimeframe"}},{"name":"limit","in":"query","description":"Results limit per category (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"events_pagination_key","in":"query","description":"Cursor for the next page of events, obtained from previous response's events_pagination.pagination_key","required":false,"schema":{"type":"string"}},{"name":"markets_pagination_key","in":"query","description":"Cursor for the next page of markets, obtained from previous response's markets_pagination.pagination_key","required":false,"schema":{"type":"string"}},{"name":"traders_pagination_key","in":"query","description":"Cursor for the next page of traders, obtained from previous response's traders_pagination.pagination_key","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Search results. Only requested categories (via `type`) are included in the response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchResponse"}}}},"400":{"description":"Bad request — q is missing or shorter than 2 characters"}}}},"/polymarket/series":{"get":{"tags":["Series"],"summary":"List or get series","description":"Retrieve series. Use `id` or `series_slug` for single lookup, `series_ids` or `series_slugs` (comma-separated, max 250, mutually exclusive) for multi-lookup, or paginate with `active_only`.","operationId":"get_series_list","parameters":[{"name":"id","in":"query","description":"Single series ID for direct lookup","required":false,"schema":{"type":"string"}},{"name":"series_ids","in":"query","description":"Comma-separated series IDs (max 250). Mutually exclusive with series_slugs.","required":false,"schema":{"type":"string"}},{"name":"series_slugs","in":"query","description":"Comma-separated series slugs (max 250). Mutually exclusive with series_ids.","required":false,"schema":{"type":"string"}},{"name":"active_only","in":"query","description":"Only active series (default: true). Ignored when series_ids or series_slugs are provided.","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor for pagination: id of the last series from the previous page","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Series or list of series","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PolymarketSeries"}}}}},"400":{"description":"series_ids and series_slugs cannot both be provided"}}}},"/polymarket/series/outcomes":{"get":{"tags":["Series"],"summary":"Get series market outcomes","description":"Returns the winning outcome name for each resolved market across all events in a series, keyed by market slug. Useful for checking historical results across recurring series (e.g., btc-updown-5m).","operationId":"get_series_outcomes","parameters":[{"name":"series_slug","in":"query","description":"Series slug (required)","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Number of resolved markets per page (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key for fetching next page","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Map of market_slug → winning outcome name with pagination metadata","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}}}}},"400":{"description":"Missing series_slug parameter"}}}},"/polymarket/tags":{"get":{"tags":["Tags"],"summary":"Get tags","description":"Retrieve all available event tags/categories. Uses cursor-based pagination for efficient traversal.","operationId":"get_tags","parameters":[{"name":"limit","in":"query","description":"Results limit (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of all tags","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PolymarketTag"}}}}}}}},"/polymarket/tags/{identifier}":{"get":{"tags":["Tags"],"summary":"Get tag by slug","description":"Retrieve a single tag by its ID or slug","operationId":"get_tag_by_id","parameters":[{"name":"identifier","in":"path","description":"Tag ID or slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Tag details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PolymarketTag"}}}},"404":{"description":"Tag not found"}}}},"/polymarket/trader/global_pnl":{"get":{"tags":["Trader"],"summary":"Get global leaderboard","description":"Retrieve the global PnL leaderboard ranked by profit and loss. Uses cursor-based pagination for efficient traversal of large datasets.","operationId":"get_global_pnl","parameters":[{"name":"timeframe","in":"query","description":"Timeframe: 1d, 7d, 30d, lifetime (default: lifetime)","required":false,"schema":{"$ref":"#/components/schemas/PnlTimeframe"}},{"name":"sort_by","in":"query","description":"Sort: pnl_usd, buys, sells, redemptions, merges, avg_hold_time, markets_traded, events_traded, markets_won, volume_usd, fees, best_trade, worst_trade (default: pnl_usd)","required":false,"schema":{"$ref":"#/components/schemas/GlobalPnlSortBy"}},{"name":"sort_direction","in":"query","description":"Sort direction: asc, desc (default: desc)","required":false,"schema":{"$ref":"#/components/schemas/SortDirection"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 200)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Global PnL leaderboard with trader stats. Response includes `pagination: { has_more, pagination_key }` for cursor-based pagination.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GlobalPnlTrader"}}}}}}}},"/polymarket/trader/pnl/{address}":{"get":{"tags":["Trader"],"summary":"Get trader PnL summary","description":"Retrieve a trader's overall profit and loss summary","operationId":"get_trader_pnl","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"timeframe","in":"query","description":"Timeframe: 1d, 7d, 30d, lifetime (default: lifetime)","required":false,"schema":{"$ref":"#/components/schemas/PnlTimeframe"}}],"responses":{"200":{"description":"Trader's global PnL summary","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TraderPnlSummary"}}}}}}},"/polymarket/trader/pnl/{address}/calendar":{"get":{"tags":["Trader"],"summary":"Get trader PnL calendar","description":"Retrieve raw per-day PnL. Each entry is the realized PnL for that calendar day. Paginate backwards using the pagination key.","operationId":"get_trader_pnl_calendar","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"days","in":"query","description":"Window size in days (default: 30, max: 30)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Pagination key obtained from a previous response to fetch an earlier window","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Daily PnL entries (one per active trading day)","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PnlCandleEntry"}}}}}}}},"/polymarket/trader/pnl/{address}/candles":{"get":{"tags":["Trader"],"summary":"Get trader PnL candles","description":"Retrieve PnL candles for charting a trader's equity curve over time.","operationId":"get_trader_pnl_candles","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Candle resolution (default: 1h)","required":false,"schema":{"$ref":"#/components/schemas/PnlCandleResolution"}},{"name":"timeframe","in":"query","description":"Time range (default: lifetime)","required":false,"schema":{"$ref":"#/components/schemas/PnlCandleTimeframe"}}],"responses":{"200":{"description":"Cumulative PnL candles","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PnlCandleEntry"}}}}}}}},"/polymarket/trader/pnl/{address}/events":{"get":{"tags":["Trader"],"summary":"Get trader event PnL","description":"Retrieve event-level PnL breakdown for a trader","operationId":"get_trader_event_pnl","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"timeframe","in":"query","description":"Timeframe: 1d, 7d, 30d, lifetime (default: lifetime)","required":false,"schema":{"$ref":"#/components/schemas/PnlTimeframe"}},{"name":"sort_by","in":"query","description":"Sort: realized_pnl_usd, total_volume_usd, markets_traded, total_fees (default: realized_pnl_usd)","required":false,"schema":{"$ref":"#/components/schemas/EventPnlSortBy"}},{"name":"sort_direction","in":"query","description":"Sort direction: asc, desc (default: desc)","required":false,"schema":{"$ref":"#/components/schemas/SortDirection"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 200)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"offset","in":"query","description":"Pagination offset (number of results to skip). Takes precedence over pagination_key.","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key obtained from previous response's pagination.pagination_key","required":false,"schema":{"type":"string"}},{"name":"event_slug","in":"query","description":"Filter by event slug","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Event-level PnL entries for this trader","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TraderEventPnlEntry"}}}}}}}},"/polymarket/trader/pnl/{address}/markets":{"get":{"tags":["Trader"],"summary":"Get trader market PnL","description":"Retrieve market-level PnL breakdown for a trader","operationId":"get_trader_market_pnl","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"timeframe","in":"query","description":"Timeframe: 1d, 7d, 30d, lifetime (default: lifetime)","required":false,"schema":{"$ref":"#/components/schemas/PnlTimeframe"}},{"name":"sort_by","in":"query","description":"Sort: realized_pnl_usd, buy_usd, total_buys, total_fees, outcomes_traded (default: realized_pnl_usd)","required":false,"schema":{"$ref":"#/components/schemas/MarketPnlSortBy"}},{"name":"sort_direction","in":"query","description":"Sort direction: asc, desc (default: desc)","required":false,"schema":{"$ref":"#/components/schemas/SortDirection"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 200)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"offset","in":"query","description":"Pagination offset (number of results to skip). Takes precedence over pagination_key.","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key obtained from previous response's pagination.pagination_key","required":false,"schema":{"type":"string"}},{"name":"condition_id","in":"query","description":"Filter by condition ID (or use market_slug)","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Filter by market slug (alternative to condition_id)","required":false,"schema":{"type":"string"}},{"name":"event_slug","in":"query","description":"Filter by event slug","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Market-level PnL entries for this trader","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TraderMarketPnlEntry"}}}}}}}},"/polymarket/trader/pnl/{address}/positions":{"get":{"tags":["Trader"],"summary":"Get trader position PnL","description":"Retrieve per-outcome-token lifetime PnL for a trader from polymarket_accounts. Includes open/closed state, win/loss outcome, redemption payouts, and share quantities. Filter by status and won/lost to segment portfolio views.","operationId":"get_trader_position_pnl","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Required. Filter by position status","required":true,"schema":{"type":"string","enum":["open","closed"]}},{"name":"won","in":"query","description":"Filter by outcome: true (won), false (lost), only for status=closed","required":false,"schema":{"type":"boolean"}},{"name":"search","in":"query","description":"Search by market title","required":false,"schema":{"type":"string"}},{"name":"sort_by","in":"query","description":"Sort field (default: realized_pnl_usd)","required":false,"schema":{"$ref":"#/components/schemas/PositionPnlSortBy"}},{"name":"sort_direction","in":"query","description":"Sort direction: asc, desc (default: desc)","required":false,"schema":{"$ref":"#/components/schemas/SortDirection"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 200)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"offset","in":"query","description":"Pagination offset","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"condition_id","in":"query","description":"Filter by market condition ID (or use market_slug)","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Filter by market slug (alternative to condition_id)","required":false,"schema":{"type":"string"}},{"name":"position_id","in":"query","description":"Filter by specific outcome token (position ID)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Position-level PnL entries for this trader. Each entry is a specific outcome token with open/closed state, avg_entry_price, avg_exit_price, and redemption info.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TraderOutcomePnlEntry"}}}}}}}},"/polymarket/trader/profile/{address}":{"get":{"tags":["Trader"],"summary":"Get trader overview","description":"Retrieve a trader's profile including stats and trading history summary","operationId":"get_trader_profile","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Trader profile information with username, bio, and badges","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PolymarketUserProfile"}}}}}}},"/polymarket/trader/profiles/batch":{"get":{"tags":["Trader"],"summary":"Get multiple trader profiles","description":"Retrieve profiles for multiple traders in a single request. Returns an array of profiles.","operationId":"get_trader_profiles_batch","parameters":[{"name":"addresses","in":"query","description":"Comma-separated list of trader addresses (max: 20)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Array of trader profiles","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PolymarketUserProfile"}}}}},"400":{"description":"Invalid request (empty addresses or more than 20)"}}}},"/polymarket/trader/trades/{address}":{"get":{"tags":["Trader"],"summary":"Get trader trades","description":"Retrieve trade history for a specific trader across all markets","operationId":"get_trader_trades","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"condition_ids","in":"query","description":"Comma-separated condition IDs (max 20)","required":false,"schema":{"type":"string"}},{"name":"slugs","in":"query","description":"Comma-separated market slugs","required":false,"schema":{"type":"string"}},{"name":"position_ids","in":"query","description":"Comma-separated position IDs","required":false,"schema":{"type":"string"}},{"name":"side","in":"query","description":"Trade side: 0 (Buy), 1 (Sell)","required":false,"schema":{"$ref":"#/components/schemas/TradeSide"}},{"name":"outcome","in":"query","description":"Outcome name filter (e.g. Yes, No)","required":false,"schema":{"type":"string"}},{"name":"outcome_index","in":"query","description":"Outcome index: 0 (Yes), 1 (No)","required":false,"schema":{"$ref":"#/components/schemas/OutcomeIndex"}},{"name":"trade_type","in":"query","description":"Trade type: 0 (OrderFilled), 1 (Redemption), 2 (Merge)","required":false,"schema":{"$ref":"#/components/schemas/TradeType"}},{"name":"min_usd_amount","in":"query","description":"Min USD amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_usd_amount","in":"query","description":"Max USD amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_shares_amount","in":"query","description":"Min shares amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_shares_amount","in":"query","description":"Max shares amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_price","in":"query","description":"Min price (0.0-1.0)","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_price","in":"query","description":"Max price (0.0-1.0)","required":false,"schema":{"type":"number","format":"double"}},{"name":"from","in":"query","description":"Start timestamp (ms)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (ms)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"all","in":"query","description":"Return all-time trades, not just last 30 days (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Results per page (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32","minimum":0}},{"name":"offset","in":"query","description":"Pagination offset (number of results to skip). Takes precedence over pagination_key.","required":false,"schema":{"type":"integer","format":"int32","minimum":0}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key obtained from previous response's pagination.pagination_key","required":false,"schema":{"type":"string"}},{"name":"sort_desc","in":"query","description":"Sort newest first (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Trader's trade history with advanced filtering (same as /market/trades but filtered by trader)","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PredictionTradeResponse"}}}}}}}},"/polymarket/trader/volume-chart/{address}":{"get":{"tags":["Trader"],"summary":"Get trader volume chart","description":"Retrieve volume breakdown by buy/sell over time for a specific trader","operationId":"get_trader_volume_chart","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Time interval: 1, 5, 15, 30, 60, 240, D, 1D (default: 60)","required":false,"schema":{"$ref":"#/components/schemas/CandlestickResolution"}},{"name":"count_back","in":"query","description":"Number of data points (max: 2500)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"from","in":"query","description":"Start timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Trader volume with buy/sell breakdown over time","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TraderVolumeDataPoint"}}}}}}}}},"components":{"schemas":{"AssetPriceHistoryRow":{"type":"object","description":"A single asset price history record from the `asset_price_history` table.","required":["asset_symbol","asset_open_price","asset_close_price","variant","start_time","end_time"],"properties":{"asset_symbol":{"type":"string"},"asset_open_price":{"type":"number","format":"double","description":"Opening price at start_time (cast to f64 from NUMERIC in query)"},"asset_close_price":{"type":"number","format":"double","description":"Closing price at end_time (cast to f64 from NUMERIC in query)"},"price_change_percentage":{"type":["number","null"],"format":"double"},"outcome":{"type":["string","null"],"description":"Generated column: \"up\" if close > open, \"down\" if close ≤ open, null if no close yet"},"variant":{"type":"string","description":"Time window: \"5m\", \"15m\", \"1h\", \"1d\""},"start_time":{"type":"integer","format":"int64","description":"Window start timestamp (seconds since epoch)"},"end_time":{"type":"integer","format":"int64","description":"Window end timestamp (seconds since epoch)"}}},"AssetSymbol":{"type":"string","enum":["BTC","ETH","XRP","SOL","DOGE","BNB","HYPE"]},"AssetVariant":{"type":"string","enum":["5m","15m","1h","4h","1d"]},"BondMarket":{"type":"object","required":["condition_id","question","market_slug","end_time","best_outcome_index","return_pct","apy","outcomes"],"properties":{"condition_id":{"type":"string"},"title":{"type":["string","null"]},"question":{"type":"string"},"market_slug":{"type":"string"},"event_slug":{"type":["string","null"]},"image_url":{"type":["string","null"]},"end_time":{"type":"integer","format":"int64"},"best_outcome_index":{"type":"integer","format":"int32","minimum":0},"return_pct":{"type":"number","format":"double"},"apy":{"type":"number","format":"double"},"volume_24h":{"type":["number","null"],"format":"double"},"outcomes":{"type":"array","items":{"$ref":"#/components/schemas/BondOutcome"}}}},"BondOutcome":{"type":"object","required":["name","index","position_id","price"],"properties":{"name":{"type":"string"},"index":{"type":"integer","format":"int32"},"position_id":{"type":"string"},"price":{"type":"number","format":"double"}}},"CandlestickResolution":{"type":"string","enum":["1","5","15","30","60","240","D","1D"]},"ClobReward":{"type":"object","description":"CLOB reward (public API format)","required":["id","condition_id"],"properties":{"id":{"type":"string"},"condition_id":{"type":"string"},"asset_address":{"type":["string","null"]},"rewards_amount":{"type":["number","null"],"format":"double"},"rewards_daily_rate":{"type":["number","null"],"format":"double"},"start_date":{"type":["string","null"]},"end_date":{"type":["string","null"]}}},"ConditionMetricsResponse":{"type":"object","description":"Response type for condition metrics query","required":["condition_id","timeframe","volume_usd","fees","txns","unique_traders"],"properties":{"condition_id":{"type":"string"},"timeframe":{"type":"string"},"volume_usd":{"type":"number","format":"double"},"fees":{"type":"number","format":"double"},"txns":{"type":"integer","format":"int32"},"unique_traders":{"type":"integer","format":"int32"}}},"ConditionOrderbookRow":{"type":"object","required":["ts","position_id","condition_id","bids","asks","hash"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"bids":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"asks":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"hash":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}},"EventMarket":{"type":"object","description":"Enriched market data for event API responses","properties":{"condition_id":{"type":"string","default":""},"id":{"type":["string","null"],"default":null},"title":{"type":["string","null"],"default":null},"question":{"type":"string","default":""},"market_slug":{"type":"string","default":""},"status":{"type":"string","default":""},"created_time":{"type":["integer","null"],"format":"int64","default":null},"end_time":{"type":["integer","null"],"format":"int64","default":null},"volume":{"type":["number","null"],"format":"double","default":null},"liquidity_usd":{"type":["number","null"],"format":"double","default":null},"volume_24hr":{"type":["number","null"],"format":"double","default":null},"image_url":{"type":["string","null"],"default":null},"market_maker_address":{"type":["string","null"],"default":null},"creator":{"type":["string","null"],"default":null},"category":{"type":["string","null"],"default":null},"accepting_orders":{"type":["boolean","null"],"default":null},"uma_resolution_status":{"type":["string","null"],"default":null},"clob_rewards":{"type":"array","items":{"$ref":"#/components/schemas/ClobReward"},"default":[]},"outcomes":{"type":"array","items":{"$ref":"#/components/schemas/EventMarketOutcome"},"default":[]},"winning_outcome":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/EventMarketOutcome"}],"default":null}}},"EventMarketChartDataPoint":{"type":"object","required":["v","t"],"properties":{"v":{"type":"number","format":"double"},"t":{"type":"integer","format":"int64","minimum":0}}},"EventMarketChartOutcome":{"type":"object","required":["condition_id","market_slug","question","title","data"],"properties":{"condition_id":{"type":"string"},"market_slug":{"type":"string"},"question":{"type":"string"},"title":{"type":"string"},"data":{"type":"array","items":{"$ref":"#/components/schemas/EventMarketChartDataPoint"}}}},"EventMarketOutcome":{"type":"object","description":"Market outcome for event API responses","required":["name"],"properties":{"name":{"type":"string"},"price":{"type":["number","null"],"format":"double"},"position_id":{"type":["string","null"]},"outcome_index":{"type":["integer","null"],"format":"int32"}}},"EventMetricsResponse":{"type":"object","description":"Response type for event metrics query","required":["event_slug","timeframe","volume_usd","fees","txns","unique_traders"],"properties":{"event_slug":{"type":"string"},"timeframe":{"type":"string"},"volume_usd":{"type":"number","format":"double"},"fees":{"type":"number","format":"double"},"txns":{"type":"integer","format":"int32"},"unique_traders":{"type":"integer","format":"int32"}}},"EventPnlSortBy":{"type":"string","enum":["realized_pnl_usd","total_volume_usd","markets_traded","total_fees","realized_pnl_pct"]},"EventSortBy":{"type":"string","enum":["volume","txns","unique_traders","title","creation_date","start_date","end_date","relevance"]},"GlobalPnlSortBy":{"type":"string","enum":["pnl_usd","buys","sells","redemptions","merges","avg_hold_time","markets_traded","events_traded","markets_won","volume_usd","fees","best_trade","worst_trade"]},"GlobalPnlTrader":{"type":"object","description":"Individual trader entry in the global PnL leaderboard","required":["trader"],"properties":{"trader":{"$ref":"#/components/schemas/TraderInfo"},"pnl_usd":{"type":["number","null"],"format":"double"},"events_traded":{"type":["integer","null"],"format":"int64"},"markets_traded":{"type":["integer","null"],"format":"int64"},"markets_won":{"type":["integer","null"],"format":"int64"},"markets_lost":{"type":["integer","null"],"format":"int64"},"market_win_rate_pct":{"type":["number","null"],"format":"double"},"total_volume_usd":{"type":["number","null"],"format":"double"},"buy_volume_usd":{"type":["number","null"],"format":"double"},"sell_volume_usd":{"type":["number","null"],"format":"double"},"redemption_volume_usd":{"type":["number","null"],"format":"double"},"merge_volume_usd":{"type":["number","null"],"format":"double"},"total_buys":{"type":["integer","null"],"format":"int64"},"total_sells":{"type":["integer","null"],"format":"int64"},"total_redemptions":{"type":["integer","null"],"format":"int64"},"total_merges":{"type":["integer","null"],"format":"int64"},"total_trades":{"type":["integer","null"],"format":"int64"},"total_fees":{"type":["number","null"],"format":"double"},"avg_pnl_per_market":{"type":["number","null"],"format":"double"},"avg_pnl_per_trade":{"type":["number","null"],"format":"double"},"avg_hold_time_seconds":{"type":["number","null"],"format":"double"},"best_trade_pnl_usd":{"type":["number","null"],"format":"double"},"best_trade_condition_id":{"type":["string","null"]},"worst_trade_pnl_usd":{"type":["number","null"],"format":"double"},"worst_trade_condition_id":{"type":["string","null"]},"first_trade_at":{"type":["integer","null"],"format":"int64"},"last_trade_at":{"type":["integer","null"],"format":"int64"}}},"Holder":{"type":"object","description":"Individual holder data","required":["trader","shares"],"properties":{"trader":{"$ref":"#/components/schemas/Trader","description":"Trader profile information"},"shares":{"type":"string","description":"Position shares held (raw balance as string for precision)"},"shares_usd":{"type":["string","null"],"description":"USD value of shares (shares * latest price)"},"usd_balance":{"type":["string","null"],"description":"USD balance of wallet (USDe on Polygon)"},"pnl":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/HolderPnl","description":"Holder-level PnL, included only when `include_pnl=true`"}]}}},"HolderHistoryCandle":{"type":"object","description":"Holder statistics data point (single time bucket)","required":["t"],"properties":{"t":{"type":"integer","format":"int64"},"h":{"type":["integer","null"],"format":"int64"}}},"HolderPnl":{"type":"object","description":"Holder-level PnL data, included when `include_pnl=true`","properties":{"avg_entry_price":{"type":["number","null"],"format":"double"},"total_cost_usd":{"type":["string","null"]},"unrealized_pnl_usd":{"type":["string","null"]},"realized_sell_pnl_usd":{"type":["string","null"]},"avg_exit_price":{"type":["number","null"],"format":"double"},"buy_usd":{"type":["number","null"],"format":"double"},"sell_usd":{"type":["number","null"],"format":"double"},"total_buys":{"type":["integer","null"],"format":"int64"},"total_sells":{"type":["integer","null"],"format":"int64"},"total_fees":{"type":["number","null"],"format":"double"},"first_trade_at":{"type":["integer","null"],"format":"int64"},"last_trade_at":{"type":["integer","null"],"format":"int64"}}},"MarketHoldersResponse":{"type":"object","description":"Response for market (condition_id) holders endpoint","required":["condition_id","total_holders","outcomes"],"properties":{"condition_id":{"type":"string","description":"Market condition ID"},"question":{"type":["string","null"],"description":"Market question/title"},"slug":{"type":["string","null"],"description":"Market slug"},"total_holders":{"type":"integer","format":"int64","description":"Total unique holders across all outcomes (from holder_stats)"},"outcomes":{"type":"array","items":{"$ref":"#/components/schemas/OutcomeHolders"},"description":"Holders grouped by outcome"}}},"MarketMetadata":{"type":"object","description":"Market metadata (enriched, cached version)","required":["condition_id","question","description","slug","neg_risk","tokens","tags","outcomes","metrics","clob_rewards"],"properties":{"condition_id":{"type":"string"},"question":{"type":"string"},"description":{"type":"string"},"slug":{"type":"string"},"event_slug":{"type":["string","null"]},"event_id":{"type":["string","null"]},"event_title":{"type":["string","null"]},"series_slug":{"type":["string","null"]},"neg_risk":{"type":"boolean"},"tokens":{"type":"array","items":{"$ref":"#/components/schemas/TokenOutcome"}},"image_url":{"type":["string","null"]},"tags":{"type":"array","items":{"type":"string"}},"created_time":{"type":["integer","null"],"format":"int64"},"start_time":{"type":["integer","null"],"format":"int64"},"game_start_time":{"type":["integer","null"],"format":"int64"},"closed_time":{"type":["integer","null"],"format":"int64"},"end_time":{"type":["integer","null"],"format":"int64"},"title":{"type":["string","null"]},"id":{"type":["string","null"]},"volume_usd":{"type":["number","null"],"format":"double"},"liquidity_usd":{"type":["number","null"],"format":"double"},"outcomes":{"type":"array","items":{"$ref":"#/components/schemas/MarketOutcome"}},"metrics":{"type":"object","additionalProperties":{"type":"number","format":"double"},"propertyNames":{"type":"string"}},"market_maker_address":{"type":["string","null"]},"creator":{"type":["string","null"]},"category":{"type":["string","null"]},"clob_rewards":{"type":"array","items":{"$ref":"#/components/schemas/ClobReward"}}}},"MarketMetadataOutcome":{"type":"object","description":"Market outcome with timeframe metrics (websocket API format)","required":["token_id","outcome"],"properties":{"token_id":{"type":"string"},"outcome":{"type":"string"},"last_price":{"type":["number","null"],"format":"double"},"last_probability":{"type":["number","null"],"format":"double"},"metrics":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/OutcomeTimeframeMetrics"},"propertyNames":{"type":"string"}}}},"MarketOutcome":{"type":"object","description":"Outcome for market API responses","properties":{"name":{"type":"string","default":""},"price":{"type":["number","null"],"format":"double","default":null},"position_id":{"type":["string","null"],"default":null},"outcome_index":{"type":["integer","null"],"format":"int32","default":null}}},"MarketPnlSortBy":{"type":"string","enum":["realized_pnl_usd","buy_usd","total_buys","total_fees","outcomes_traded","realized_pnl_pct"]},"MarketResponse":{"type":"object","description":"Formatted market response with structured metrics, tags, outcomes, and event","required":["condition_id","status"],"properties":{"condition_id":{"type":"string"},"id":{"type":["string","null"]},"market_slug":{"type":["string","null"]},"question":{"type":["string","null"]},"title":{"type":["string","null"]},"description":{"type":["string","null"]},"image_url":{"type":["string","null"]},"oracle":{"type":["string","null"]},"status":{"type":"string"},"created_time":{"type":["integer","null"],"format":"int64"},"start_time":{"type":["integer","null"],"format":"int64"},"game_start_time":{"type":["integer","null"],"format":"int64"},"closed_time":{"type":["integer","null"],"format":"int64"},"end_time":{"type":["integer","null"],"format":"int64"},"accepting_orders":{"type":["boolean","null"]},"uma_resolution_status":{"type":["string","null"]},"is_neg_risk":{"type":["boolean","null"]},"market_maker_address":{"type":["string","null"]},"creator":{"type":["string","null"]},"category":{"type":["string","null"]},"volume_usd":{"type":["number","null"],"format":"double"},"liquidity_usd":{"type":["number","null"],"format":"double"},"highest_probability":{"type":["number","null"],"format":"double"},"total_holders":{"type":["integer","null"],"format":"int64"},"winning_outcome":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/MarketOutcome"}]},"outcomes":{"type":"array","items":{"$ref":"#/components/schemas/MarketOutcome"}},"rewards":{"type":"array","items":{"$ref":"#/components/schemas/MarketReward"}},"clob_rewards":{"type":"array","items":{"$ref":"#/components/schemas/ClobReward"}},"tags":{"type":"array","items":{"type":"string"}},"event_slug":{"type":["string","null"]},"resolution_source":{"type":["string","null"]},"metrics":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/SimpleTimeframeMetrics"},"propertyNames":{"type":"string"}},"relevance_score":{"type":["number","null"],"format":"double"}}},"MarketReward":{"type":"object","description":"Reward info for market API responses","properties":{"min_size":{"type":["number","null"],"format":"double","default":null},"max_spread":{"type":["number","null"],"format":"double","default":null},"daily_rate":{"type":["number","null"],"format":"double","default":null}}},"MarketSortBy":{"type":"string","enum":["volume","txns","unique_traders","liquidity","holders","end_time","start_time","created_time","relevance"]},"MarketStatus":{"type":"string","enum":["open","closed","all"]},"MarketVolumeChartResponse":{"type":"object","required":["volumes","has_more"],"properties":{"volumes":{"type":"array","items":{"$ref":"#/components/schemas/MarketVolumeDataPoint"}},"has_more":{"type":"boolean"}}},"MarketVolumeDataPoint":{"type":"object","required":["t","v","yv","nv","tc","ytc","ntc"],"properties":{"t":{"type":"integer","format":"int64"},"v":{"type":"number","format":"double"},"yv":{"type":"number","format":"double"},"nv":{"type":"number","format":"double"},"tc":{"type":"integer","format":"int32"},"ytc":{"type":"integer","format":"int32"},"ntc":{"type":"integer","format":"int32"}}},"MetricsTimeframe":{"type":"string","enum":["1m","5m","30m","1h","6h","24h","7d","30d"]},"OrderbookHistoryRow":{"type":"object","required":["ts","position_id","condition_id","bids","asks","hash"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"bids":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"asks":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"hash":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}},"OrderbookLevel":{"type":"object","description":"A single price level in a bids/asks array.","required":["p","s"],"properties":{"p":{"type":"string","description":"Price as a decimal string"},"s":{"type":"string","description":"Size as a decimal string"}}},"OrderbookSnapshotRow":{"type":"object","required":["ts","position_id","condition_id","bids","asks","hash"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"bids":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"asks":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"hash":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}},"OutcomeHolders":{"type":"object","description":"Holder data grouped by outcome for market-level queries","required":["outcome_index","outcome_name","position_id","total_holders","holders"],"properties":{"outcome_index":{"type":"integer","format":"int32","description":"Outcome index (0, 1, etc.)"},"outcome_name":{"type":"string","description":"Outcome name (Yes, No, etc.)"},"position_id":{"type":"string","description":"Position ID for this outcome"},"price":{"type":["number","null"],"format":"double","description":"Current price/probability"},"total_holders":{"type":"integer","format":"int64","description":"Total holders count from holder_stats"},"holders":{"type":"array","items":{"$ref":"#/components/schemas/Holder"},"description":"Top holders for this outcome"}}},"OutcomeIndex":{"type":"string","enum":["0","1"]},"OutcomeTimeframeMetrics":{"type":"object","properties":{"volume":{"type":"number","format":"double","default":0},"buy_volume":{"type":"number","format":"double","default":0},"sell_volume":{"type":"number","format":"double","default":0},"txns":{"type":"integer","format":"int32","default":0},"buys":{"type":"integer","format":"int32","default":0},"sells":{"type":"integer","format":"int32","default":0},"price_open":{"type":["number","null"],"format":"double","default":null},"price_close":{"type":["number","null"],"format":"double","default":null},"price_high":{"type":["number","null"],"format":"double","default":null},"price_low":{"type":["number","null"],"format":"double","default":null},"probability_open":{"type":["number","null"],"format":"double","default":null},"probability_close":{"type":["number","null"],"format":"double","default":null},"probability_high":{"type":["number","null"],"format":"double","default":null},"probability_low":{"type":["number","null"],"format":"double","default":null},"price_change_percent":{"type":["number","null"],"format":"double","default":null}}},"PaginationMeta":{"type":"object","description":"Pagination metadata to include in API responses","required":["has_more"],"properties":{"has_more":{"type":"boolean","description":"Whether there are more results available"},"pagination_key":{"type":["string","null"],"description":"Pagination key for the next page (if has_more is true)"}}},"PnlCandleEntry":{"type":"object","description":"A single PnL candle entry","required":["t","pnl"],"properties":{"t":{"type":"integer","format":"int64","description":"Timestamp in epoch seconds (start of bucket window)"},"pnl":{"type":"number","format":"double","description":"Realized PnL in this bucket (USD)"}}},"PnlCandleResolution":{"type":"string","enum":["1m","1h","1d"]},"PnlCandleTimeframe":{"type":"string","enum":["1d","7d","30d","lifetime"]},"PnlTimeframe":{"type":"string","enum":["1d","7d","30d","lifetime"]},"PolymarketEvent":{"type":"object","description":"A Polymarket event from the Gamma API","properties":{"id":{"type":"string","default":""},"event_slug":{"type":["string","null"],"default":null},"title":{"type":["string","null"],"default":null},"ticker":{"type":["string","null"],"default":null},"description":{"type":["string","null"],"default":null},"resolution_source":{"type":["string","null"],"default":null},"category":{"type":["string","null"],"default":null},"image_url":{"type":["string","null"],"default":null},"market_count":{"type":"integer","format":"int32","default":0},"created_time":{"type":["integer","null"],"format":"int64","default":null},"closed_time":{"type":["integer","null"],"format":"int64","default":null},"start_time":{"type":["integer","null"],"format":"int64","default":null},"end_time":{"type":["integer","null"],"format":"int64","default":null},"neg_risk":{"type":"boolean","default":false},"neg_risk_market_id":{"type":["string","null"],"default":null},"game_status":{"type":["string","null"],"default":null},"show_market_images":{"type":"boolean","default":false},"status":{"type":["string","null"],"description":"Event status: \"open\" or \"closed\"","default":null},"metrics":{"type":"object","default":{},"additionalProperties":{"$ref":"#/components/schemas/SimpleTimeframeMetrics"},"propertyNames":{"type":"string"}},"tags":{"type":"array","items":{"$ref":"#/components/schemas/PolymarketTag"},"default":[]},"markets":{"type":"array","items":{"$ref":"#/components/schemas/EventMarket"},"default":[]},"series":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PolymarketSeries"}],"default":null}}},"PolymarketSeries":{"type":"object","description":"A Polymarket series from the Gamma API\nSeries are parent groupings above events (e.g., \"NBA Season 2024-25\")","properties":{"id":{"type":"string","default":""},"slug":{"type":["string","null"],"default":null},"ticker":{"type":["string","null"],"default":null},"title":{"type":["string","null"],"default":null},"description":{"type":["string","null"],"default":null},"series_type":{"type":["string","null"],"default":null},"recurrence":{"type":["string","null"],"default":null},"layout":{"type":["string","null"],"default":null},"image_url":{"type":["string","null"],"default":null},"icon_url":{"type":["string","null"],"default":null},"active":{"type":"boolean","default":false},"closed":{"type":"boolean","default":false},"archived":{"type":"boolean","default":false},"featured":{"type":"boolean","default":false},"restricted":{"type":"boolean","default":false},"pyth_token_id":{"type":["string","null"],"default":null},"cg_asset_name":{"type":["string","null"],"default":null},"start_date":{"type":["integer","null"],"format":"int64","default":null},"event_count":{"type":"integer","format":"int32","default":0}}},"PolymarketTag":{"type":"object","description":"A Polymarket tag from the Gamma API","properties":{"id":{"type":"string","default":""},"label":{"type":"string","default":""},"slug":{"type":["string","null"],"default":null}}},"PolymarketUserProfile":{"type":"object","description":"Polymarket user profile (public API format)","required":["proxy_wallet","display_username_public","verified_badge","is_creator","is_mod"],"properties":{"proxy_wallet":{"type":"string"},"name":{"type":["string","null"]},"pseudonym":{"type":["string","null"]},"bio":{"type":["string","null"]},"profile_image":{"type":["string","null"]},"x_username":{"type":["string","null"]},"display_username_public":{"type":"boolean"},"verified_badge":{"type":"boolean"},"user_id":{"type":["string","null"]},"is_creator":{"type":"boolean"},"is_mod":{"type":"boolean"},"created_at":{"type":["string","null"]}}},"PositionChartDataPoint":{"type":"object","required":["v","t"],"properties":{"v":{"type":"number","format":"double"},"t":{"type":"integer","format":"int64","minimum":0}}},"PositionChartOutcome":{"type":"object","required":["position_id","name","outcome_index","data"],"properties":{"position_id":{"type":"string"},"name":{"type":"string"},"outcome_index":{"type":"integer","format":"int32"},"data":{"type":"array","items":{"$ref":"#/components/schemas/PositionChartDataPoint"}}}},"PositionHoldersResponse":{"type":"object","description":"Response for position (position_id) holders endpoint","required":["position_id","total_holders","holders"],"properties":{"position_id":{"type":"string","description":"Position ID (ERC1155 token ID)"},"condition_id":{"type":["string","null"],"description":"Condition ID this position belongs to"},"outcome_name":{"type":["string","null"],"description":"Outcome name"},"outcome_index":{"type":["integer","null"],"format":"int32","description":"Outcome index"},"price":{"type":["number","null"],"format":"double","description":"Current price"},"total_holders":{"type":"integer","format":"int64","description":"Total holders count from holder_stats"},"holders":{"type":"array","items":{"$ref":"#/components/schemas/Holder"},"description":"Top holders"}}},"PositionMetricsResponse":{"type":"object","description":"Response type for position metrics query","required":["position_id","condition_id","timeframe","volume_usd","buy_volume_usd","sell_volume_usd","fees","txns","buys","sells","unique_traders","price_open","price_high","price_low","price_close"],"properties":{"position_id":{"type":"string"},"condition_id":{"type":"string"},"timeframe":{"type":"string"},"volume_usd":{"type":"number","format":"double"},"buy_volume_usd":{"type":"number","format":"double"},"sell_volume_usd":{"type":"number","format":"double"},"fees":{"type":"number","format":"double"},"txns":{"type":"integer","format":"int32"},"buys":{"type":"integer","format":"int32"},"sells":{"type":"integer","format":"int32"},"unique_traders":{"type":"integer","format":"int32"},"price_open":{"type":"number","format":"double"},"price_high":{"type":"number","format":"double"},"price_low":{"type":"number","format":"double"},"price_close":{"type":"number","format":"double"}}},"PositionPnlSortBy":{"type":"string","enum":["realized_pnl_usd","buy_usd","sell_usd","redemption_usd","total_buys","total_sells","total_shares_bought","total_shares_sold","avg_entry_price","avg_exit_price","total_fees","first_trade_at","last_trade_at","current_value","realized_pnl_pct","title"]},"PositionVolumeChartResponse":{"type":"object","required":["volumes","has_more"],"properties":{"volumes":{"type":"array","items":{"$ref":"#/components/schemas/PositionVolumeDataPoint"}},"has_more":{"type":"boolean"}}},"PositionVolumeDataPoint":{"type":"object","required":["t","v","bv","sv","tc","btc","stc"],"properties":{"t":{"type":"integer","format":"int64"},"v":{"type":"number","format":"double"},"bv":{"type":"number","format":"double"},"sv":{"type":"number","format":"double"},"tc":{"type":"integer","format":"int32"},"btc":{"type":"integer","format":"int32"},"stc":{"type":"integer","format":"int32"}}},"PredictionCandlestickBar":{"type":"object","required":["t"],"properties":{"l":{"type":["number","null"],"format":"double"},"h":{"type":["number","null"],"format":"double"},"o":{"type":["number","null"],"format":"double"},"c":{"type":["number","null"],"format":"double"},"v":{"type":["number","null"],"format":"double"},"t":{"type":"integer","format":"int64","minimum":0},"tc":{"type":["integer","null"],"format":"int32"},"m":{"type":["number","null"],"format":"double"}}},"PredictionTradeResponse":{"type":"object","description":"Response format for prediction trades","required":["id","hash","block","confirmed_at","trader","taker","usd_amount","shares_amount","price","fee","exchange","trade_type","log_index","order_hash","position_id"],"properties":{"id":{"type":"string"},"hash":{"type":"string"},"block":{"type":"integer","format":"int64","minimum":0},"confirmed_at":{"type":"integer","format":"int64","minimum":0},"trader":{"$ref":"#/components/schemas/TraderInfo"},"taker":{"type":"string"},"side":{"type":["string","null"]},"condition_id":{"type":["string","null"]},"outcome":{"type":["string","null"]},"outcome_index":{"type":["integer","null"],"format":"int32"},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"slug":{"type":["string","null"]},"usd_amount":{"type":"number","format":"double"},"shares_amount":{"type":"number","format":"double"},"price":{"type":"number","format":"double"},"probability":{"type":["number","null"],"format":"double"},"fee":{"type":"number","format":"double"},"exchange":{"type":"string"},"trade_type":{"type":"string"},"log_index":{"type":"integer","format":"int64","minimum":0},"order_hash":{"type":"string"},"position_id":{"type":"string"}}},"PriceJump":{"type":"object","required":["from","to","price_before","price_after","change_pct","direction","volume","trades_count","condition_id"],"properties":{"from":{"type":"integer","format":"int64","minimum":0},"to":{"type":"integer","format":"int64","minimum":0},"price_before":{"type":"number","format":"double"},"price_after":{"type":"number","format":"double"},"change_pct":{"type":"number","format":"double"},"direction":{"type":"string"},"volume":{"type":"number","format":"double"},"trades_count":{"type":"integer","format":"int32"},"condition_id":{"type":"string"}}},"SearchResponse":{"type":"object","properties":{"events":{"type":["array","null"],"items":{"$ref":"#/components/schemas/PolymarketEvent"}},"events_pagination":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PaginationMeta"}]},"markets":{"type":["array","null"],"items":{"$ref":"#/components/schemas/MarketResponse"}},"markets_pagination":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PaginationMeta"}]},"traders":{"type":["array","null"],"items":{"$ref":"#/components/schemas/TraderWithPnl"}},"traders_pagination":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PaginationMeta"}]}}},"SearchSortBy":{"type":"string","description":"Combined sort options valid for both events and markets in search","enum":["volume","txns","unique_traders","relevance","title","creation_date","start_date","end_date","liquidity","holders","end_time","start_time","created_time"]},"SimpleTimeframeMetrics":{"type":"object","properties":{"volume":{"type":"number","format":"double","default":0},"fees":{"type":"number","format":"double","default":0},"txns":{"type":"integer","format":"int32","default":0},"unique_traders":{"type":"integer","format":"int32","default":0}}},"SortDirection":{"type":"string","enum":["asc","desc"]},"SpikeDirection":{"type":"string","description":"Direction filter for spike webhooks.","enum":["up","down","both"]},"SpreadRow":{"type":"object","description":"Lightweight row — derived metrics only, no bids/asks JSONB.","required":["ts","position_id","condition_id"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}},"TokenOutcome":{"type":"object","description":"Token outcome (position)","required":["token_id","outcome"],"properties":{"token_id":{"type":"string"},"outcome":{"type":"string"}}},"TradeSide":{"type":"string","enum":["0","1"]},"TradeType":{"type":"string","enum":["0","1","2","4","6"]},"Trader":{"type":"object","description":"Trader profile info embedded in API responses\n\nCorresponds to SQL function: `pm_build_trader(address, name, pseudonym, profile_image, x_username, verified_badge)`\n\nUsed in:\n- holders endpoints (market/event holders)\n- trades endpoints\n- leaderboard endpoints","required":["address"],"properties":{"address":{"type":"string"},"name":{"type":["string","null"]},"pseudonym":{"type":["string","null"]},"profile_image":{"type":["string","null"]},"x_username":{"type":["string","null"]},"verified_badge":{"type":"boolean"}}},"TraderEventPnlEntry":{"type":"object","description":"Event-level PnL entry","properties":{"event_slug":{"type":["string","null"]},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"markets_traded":{"type":["integer","null"],"format":"int64"},"outcomes_traded":{"type":["integer","null"],"format":"int64"},"total_buys":{"type":["integer","null"],"format":"int64"},"total_sells":{"type":["integer","null"],"format":"int64"},"total_redemptions":{"type":["integer","null"],"format":"int64"},"total_merges":{"type":["integer","null"],"format":"int64"},"total_volume_usd":{"type":["number","null"],"format":"double"},"buy_usd":{"type":["number","null"],"format":"double"},"sell_usd":{"type":["number","null"],"format":"double"},"redemption_usd":{"type":["number","null"],"format":"double"},"merge_usd":{"type":["number","null"],"format":"double"},"realized_pnl_usd":{"type":["number","null"],"format":"double"},"winning_markets":{"type":["integer","null"],"format":"int64"},"losing_markets":{"type":["integer","null"],"format":"int64"},"total_fees":{"type":["number","null"],"format":"double"},"first_trade_at":{"type":["integer","null"],"format":"int64"},"last_trade_at":{"type":["integer","null"],"format":"int64"}}},"TraderInfo":{"type":"object","description":"Trader profile info - backwards compatibility","required":["address"],"properties":{"address":{"type":"string"},"name":{"type":["string","null"]},"pseudonym":{"type":["string","null"]},"profile_image":{"type":["string","null"]},"x_username":{"type":["string","null"]},"verified_badge":{"type":"boolean"}}},"TraderMarketPnlEntry":{"type":"object","description":"Market-level PnL entry","properties":{"condition_id":{"type":["string","null"]},"event_slug":{"type":["string","null"]},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"outcomes_traded":{"type":["integer","null"],"format":"int64"},"total_buys":{"type":["integer","null"],"format":"int64"},"total_sells":{"type":["integer","null"],"format":"int64"},"total_redemptions":{"type":["integer","null"],"format":"int64"},"total_merges":{"type":["integer","null"],"format":"int64"},"buy_usd":{"type":["number","null"],"format":"double"},"sell_usd":{"type":["number","null"],"format":"double"},"redemption_usd":{"type":["number","null"],"format":"double"},"merge_usd":{"type":["number","null"],"format":"double"},"realized_pnl_usd":{"type":["number","null"],"format":"double"},"winning_outcomes":{"type":["integer","null"],"format":"int64"},"total_fees":{"type":["number","null"],"format":"double"},"first_trade_at":{"type":["integer","null"],"format":"int64"},"last_trade_at":{"type":["integer","null"],"format":"int64"}}},"TraderOutcomePnlEntry":{"type":"object","description":"Outcome-level PnL entry (per outcome token / position_id)","properties":{"position_id":{"type":["string","null"]},"condition_id":{"type":["string","null"]},"market_slug":{"type":["string","null"]},"event_slug":{"type":["string","null"]},"title":{"type":["string","null"]},"image_url":{"type":["string","null"]},"outcome":{"type":["string","null"]},"outcome_index":{"type":["integer","null"],"format":"int32"},"won":{"type":["boolean","null"],"description":"TRUE = won, FALSE = lost, NULL = open or sold before resolution"},"total_buys":{"type":["integer","null"],"format":"int64"},"total_sells":{"type":["integer","null"],"format":"int64"},"total_shares_bought":{"type":["number","null"],"format":"double"},"total_shares_sold":{"type":["number","null"],"format":"double"},"total_buy_usd":{"type":["number","null"],"format":"double"},"total_sell_usd":{"type":["number","null"],"format":"double"},"redemption_usd":{"type":["number","null"],"format":"double","description":"Payout on redemption (non-zero only if won)"},"avg_entry_price":{"type":["number","null"],"format":"double","description":"VWAP price paid per share across all buys (0–1)"},"avg_exit_price":{"type":["number","null"],"format":"double","description":"VWAP price received per share across all sells (0–1)"},"realized_pnl_usd":{"type":["number","null"],"format":"double"},"total_fees":{"type":["number","null"],"format":"double"},"first_trade_at":{"type":["integer","null"],"format":"int64"},"last_trade_at":{"type":["integer","null"],"format":"int64"},"current_price":{"type":["number","null"],"format":"double","description":"Last traded price for this outcome (0–1). NULL if market_outcomes has no price yet."},"current_shares_balance":{"type":["number","null"],"format":"double","description":"Current shares held: balance / 1e6."},"current_value":{"type":["number","null"],"format":"double","description":"Estimated current USD value of held shares: (balance / 1e6) * current_price.\nOnly meaningful for open positions (balance > 0)."},"realized_pnl_pct":{"type":["number","null"],"format":"double","description":"Realized PnL as a percentage of total spend: (realized_pnl_usd / total_buy_usd) * 100.\nNULL when total_buy_usd = 0."}}},"TraderPnlSummary":{"type":"object","description":"Trader's global PnL summary (single trader)","properties":{"trader":{"type":["string","null"]},"realized_pnl_usd":{"type":["number","null"],"format":"double"},"events_traded":{"type":["integer","null"],"format":"int64"},"markets_traded":{"type":["integer","null"],"format":"int64"},"total_buys":{"type":["integer","null"],"format":"int64"},"total_sells":{"type":["integer","null"],"format":"int64"},"total_redemptions":{"type":["integer","null"],"format":"int64"},"total_merges":{"type":["integer","null"],"format":"int64"},"total_volume_usd":{"type":["number","null"],"format":"double"},"buy_volume_usd":{"type":["number","null"],"format":"double"},"sell_volume_usd":{"type":["number","null"],"format":"double"},"redemption_volume_usd":{"type":["number","null"],"format":"double"},"merge_volume_usd":{"type":["number","null"],"format":"double"},"markets_won":{"type":["integer","null"],"format":"int64"},"markets_lost":{"type":["integer","null"],"format":"int64"},"market_win_rate_pct":{"type":["number","null"],"format":"double"},"avg_pnl_per_market":{"type":["number","null"],"format":"double"},"avg_pnl_per_trade":{"type":["number","null"],"format":"double"},"avg_hold_time_seconds":{"type":["number","null"],"format":"double"},"total_fees":{"type":["number","null"],"format":"double"},"best_trade_pnl_usd":{"type":["number","null"],"format":"double"},"best_trade_condition_id":{"type":["string","null"]},"worst_trade_pnl_usd":{"type":["number","null"],"format":"double"},"worst_trade_condition_id":{"type":["string","null"]},"first_trade_at":{"type":["integer","null"],"format":"int64"},"last_trade_at":{"type":["integer","null"],"format":"int64"}}},"TraderVolumeChartResponse":{"type":"object","required":["volumes","has_more"],"properties":{"volumes":{"type":"array","items":{"$ref":"#/components/schemas/TraderVolumeDataPoint"}},"has_more":{"type":"boolean"}}},"TraderVolumeDataPoint":{"type":"object","required":["t","v","bv","sv","tc","btc","stc"],"properties":{"t":{"type":"integer","format":"int64"},"v":{"type":"number","format":"double"},"bv":{"type":"number","format":"double"},"sv":{"type":"number","format":"double"},"tc":{"type":"integer","format":"int32"},"btc":{"type":"integer","format":"int32"},"stc":{"type":"integer","format":"int32"}}},"TraderWithPnl":{"allOf":[{"$ref":"#/components/schemas/Trader"},{"type":"object","properties":{"pnl":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/TraderPnlSummary"}]}}}]},"WebhookAssetSymbol":{"type":"string","description":"Crypto asset symbols accepted by `asset_price_tick` and `asset_price_window_update` filters.","enum":["BTC","ETH","SOL","XRP","DOGE","BNB","HYPE"]},"WebhookTimeframe":{"type":"string","description":"Timeframe values accepted by webhook metric, milestone, spike, and asset-price filters.","enum":["1m","5m","15m","30m","1h","4h","6h","1d","24h","7d","30d"]}}}} \ No newline at end of file +{"openapi":"3.1.0","info":{"title":"Polymarket API","description":"RESTful API for querying Polymarket prediction markets data including events, markets, traders, holders, and real-time metrics","license":{"name":""},"version":"1.0.0"},"servers":[{"url":"https://api.struct.to/v1","description":"Production"}],"paths":{"/polymarket/asset-history":{"get":{"tags":["Assets"],"summary":"Get Asset Price History","description":"Returns historical price data for supported crypto assets from Polymarket API","operationId":"get_asset_history","parameters":[{"name":"asset_symbol","in":"query","description":"Asset ticker: BTC, ETH, XRP, SOL, DOGE, BNB, HYPE","required":true,"schema":{"type":"string"},"example":"BTC"},{"name":"variant","in":"query","description":"Time window: 5m, 15m, 1h, 4h, 1d","required":true,"schema":{"type":"string"},"example":"1h"},{"name":"from","in":"query","description":"Start timestamp in seconds (Unix epoch, inclusive)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp in seconds (Unix epoch, inclusive)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"limit","in":"query","description":"Number of results (default: 10, max: 100)","required":false,"schema":{"type":"integer","format":"int64"},"example":10}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AssetPriceHistoryRow"}}}}},"400":{"description":"Bad request - missing or invalid parameters"},"500":{"description":"Internal server error"}}}},"/polymarket/events":{"get":{"tags":["Events"],"summary":"Get events","description":"Retrieve a paginated list of events with filtering, sorting, and optional nested tags/markets","operationId":"get_events","parameters":[{"name":"id","in":"query","description":"Filter by event ID(s) - comma-separated (max 50). Cannot be used with 'event_slugs'. Example: id=99600,99601,99583","required":false,"schema":{"type":"string"}},{"name":"event_slugs","in":"query","description":"Filter by event slug(s) - comma-separated (max 50). Cannot be used with 'id'. Example: event_slugs=will-trump-win,bitcoin-100k","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","description":"Search in title and description (3-100 characters). Example: search=trump","required":false,"schema":{"type":"string"}},{"name":"sort_by","in":"query","description":"Sort: volume, txns, unique_traders, title, creation_date, start_date, end_date, relevance (relevance only works in search mode) (default: volume)","required":false,"schema":{"$ref":"#/components/schemas/EventSortBy"}},{"name":"sort_dir","in":"query","description":"Sort direction: asc, desc (default: desc)","required":false,"schema":{"$ref":"#/components/schemas/SortDirection"}},{"name":"timeframe","in":"query","description":"Metrics timeframe: 1m, 5m, 30m, 1h, 6h, 24h, 7d, 30d (default: 24h)","required":false,"schema":{"$ref":"#/components/schemas/MetricsTimeframe"}},{"name":"status","in":"query","description":"Filter by status: open, closed, or all (default: all)","required":false,"schema":{"$ref":"#/components/schemas/MarketStatus"}},{"name":"categories","in":"query","description":"Comma-separated category filters","required":false,"schema":{"type":"string"}},{"name":"exclude_categories","in":"query","description":"Comma-separated categories to exclude","required":false,"schema":{"type":"string"}},{"name":"tags","in":"query","description":"Filter by tag slug(s) - comma-separated (max 50). Example: tags=sports,football,crypto","required":false,"schema":{"type":"string"}},{"name":"exclude_tags","in":"query","description":"Comma-separated tag slugs to exclude","required":false,"schema":{"type":"string"}},{"name":"min_volume","in":"query","description":"Minimum volume in selected timeframe","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_volume","in":"query","description":"Maximum volume in selected timeframe","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_txns","in":"query","description":"Minimum transactions in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"max_txns","in":"query","description":"Maximum transactions in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"min_unique_traders","in":"query","description":"Minimum unique traders in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"max_unique_traders","in":"query","description":"Maximum unique traders in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"include_tags","in":"query","description":"Include tags array (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_markets","in":"query","description":"Include markets array with outcomes (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_metrics","in":"query","description":"Include metrics object with all timeframes (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key","required":false,"schema":{"type":"string"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of Polymarket events with nested tags, markets, and series. Response includes `pagination: { has_more, pagination_key }` for cursor-based pagination.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PolymarketEvent"}}}}},"400":{"description":"Bad request - validation error (search length, array limits, conflicting params)"}}}},"/polymarket/events/chart":{"get":{"tags":["Events"],"summary":"Get event chart","description":"Retrieve price data over time for up to 4 markets with highest YES outcome (outcome_index 0) prices in an event. Perfect for rendering multi-line charts showing price movement across top markets. TradingView-style: resolution parameter determines both candle size and implicit lookback period.","operationId":"get_event_chart","parameters":[{"name":"event_slug","in":"query","description":"Event slug (required)","required":true,"schema":{"type":"string"}},{"name":"condition_ids","in":"query","description":"Comma-separated condition IDs to include (max 4, optional)","required":false,"schema":{"type":"string"}},{"name":"market_slugs","in":"query","description":"Comma-separated market slugs to include (max 4, optional). Use either condition_ids or market_slugs, not both","required":false,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Time interval with implicit lookback: 1H (1 hour), 6H (6 hours), 1D (1 day), 1W (1 week), 1M (30 days), ALL (all data) (required)","required":true,"schema":{"type":"string","enum":["1H","6H","1D","1W","1M","ALL"]}}],"responses":{"200":{"description":"Price data over time for up to 4 markets with highest YES odds","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventMarketChartOutcome"}}}}}}}},"/polymarket/events/metrics":{"get":{"tags":["Events"],"summary":"Get event metrics","description":"Retrieve volume, transaction, and trader metrics for an event. Supports single timeframe (e.g., '1m'), multiple timeframes (e.g., '1m,5m,1h'), or 'all' to get all available timeframes.","operationId":"get_event_metrics","parameters":[{"name":"event_slug","in":"query","description":"Event slug","required":true,"schema":{"type":"string"}},{"name":"timeframe","in":"query","description":"Timeframe: single (1m, 5m, 30m, 1h, 6h, 24h, 7d, 30d), comma-separated (1m,5m,1h), or 'all'","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Event metrics for the specified timeframe(s). Returns single object for one timeframe, array for multiple.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventMetricsResponse"}}}},"400":{"description":"Invalid timeframe"}}}},"/polymarket/events/outcomes":{"get":{"tags":["Events"],"summary":"Get event market outcomes","description":"Returns the winning outcome name for each resolved market in an event, keyed by market slug. Useful for quickly checking which outcomes won across a series.","operationId":"get_event_outcomes","parameters":[{"name":"event_slug","in":"query","description":"Event slug (required)","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Number of resolved markets per page (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key for fetching next page","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Map of market_slug → winning outcome name with pagination metadata","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}}}}},"400":{"description":"Missing event_slug parameter"}}}},"/polymarket/events/slug/{slug}":{"get":{"tags":["Events"],"summary":"Get event by slug","description":"Retrieve a single event by its slug with optional nested tags, markets, and metrics","operationId":"get_event_by_slug","parameters":[{"name":"slug","in":"path","description":"Event slug","required":true,"schema":{"type":"string"}},{"name":"include_tags","in":"query","description":"Include tags array (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_markets","in":"query","description":"Include markets array with outcomes (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_metrics","in":"query","description":"Include metrics object with all timeframes (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Event with nested tags, markets, and series","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PolymarketEvent"}}}},"404":{"description":"Event not found"}}}},"/polymarket/events/{identifier}":{"get":{"tags":["Events"],"summary":"Get event by ID or slug","description":"Retrieve a single event by its numeric ID or slug with optional nested tags, markets, and metrics","operationId":"get_event","parameters":[{"name":"identifier","in":"path","description":"Event ID or slug","required":true,"schema":{"type":"string"}},{"name":"include_tags","in":"query","description":"Include tags array (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_markets","in":"query","description":"Include markets array with outcomes (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_metrics","in":"query","description":"Include metrics object with all timeframes (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Event with nested tags, markets, and series","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PolymarketEvent"}}}},"404":{"description":"Event not found"}}}},"/polymarket/holders/markets":{"get":{"tags":["Holders"],"summary":"Get market holders","description":"Retrieve holders of a market grouped by outcome, sorted by shares held. Identify the market with either `condition_id` or `market_slug` — exactly one must be provided. Set `include_pnl=true` to include a nested holder `pnl` object.","operationId":"get_market_holders","parameters":[{"name":"condition_id","in":"query","description":"Market condition ID (0x-prefixed hex)","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (e.g. `will-trump-win`)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"min_shares","in":"query","description":"Minimum shares held (decimal string)","required":false,"schema":{"type":"string"}},{"name":"max_shares","in":"query","description":"Maximum shares held (decimal string)","required":false,"schema":{"type":"string"}},{"name":"include_pnl","in":"query","description":"Include nested holder PnL data (default: false, +1 credit)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Market holders grouped by outcome (sorted by shares DESC). Holder `pnl` is included only when `include_pnl=true`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarketHoldersResponse"}}}},"404":{"description":"Market not found"}}}},"/polymarket/holders/markets/history":{"get":{"tags":["Holders"],"summary":"Get market holders history","description":"Retrieve historical holder count snapshots for a market over a time range. Identify the market with either `condition_id` or `market_slug` — exactly one must be provided.","operationId":"get_market_holders_history","parameters":[{"name":"condition_id","in":"query","description":"Market condition ID (0x-prefixed hex)","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (e.g. `will-trump-win`)","required":false,"schema":{"type":"string"}},{"name":"hours","in":"query","description":"Time range in hours (default: 24, max: 336 = 14 days)","required":false,"schema":{"type":"number","format":"double"}}],"responses":{"200":{"description":"Market holder count history with automatic granularity (1m/5m/15m/1h/6h buckets)","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/HolderHistoryCandle"}}}}},"404":{"description":"Market not found"}}}},"/polymarket/holders/positions/{position_id}":{"get":{"tags":["Holders"],"summary":"Get position holders","description":"Retrieve holders of a specific position (ERC1155 token), sorted by shares held. Set `include_pnl=true` to include nested holder PnL. Uses cursor-based pagination for efficient traversal.","operationId":"get_position_holders","parameters":[{"name":"position_id","in":"path","description":"Position ID (ERC1155 token ID)","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key","required":false,"schema":{"type":"string"}},{"name":"min_shares","in":"query","description":"Minimum shares held (decimal string)","required":false,"schema":{"type":"string"}},{"name":"max_shares","in":"query","description":"Maximum shares held (decimal string)","required":false,"schema":{"type":"string"}},{"name":"include_pnl","in":"query","description":"Include nested holder PnL data (default: false, +1 credit)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Position holders (sorted by shares DESC). Holder `pnl` is included only when `include_pnl=true`. Response includes `pagination: { has_more, pagination_key }` for cursor-based pagination.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PositionHoldersResponse"}}}},"404":{"description":"Position not found"}}}},"/polymarket/holders/positions/{position_id}/history":{"get":{"tags":["Holders"],"summary":"Get position holders history","description":"Retrieve historical holder count snapshots for a position over a time range","operationId":"get_position_holders_history","parameters":[{"name":"position_id","in":"path","description":"Position ID (ERC1155 token ID)","required":true,"schema":{"type":"string"}},{"name":"hours","in":"query","description":"Time range in hours (default: 24, max: 336 = 14 days)","required":false,"schema":{"type":"number","format":"double"}}],"responses":{"200":{"description":"Position holder count history with automatic granularity (1m/5m/15m/1h/6h buckets)","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/HolderHistoryCandle"}}}}},"404":{"description":"Position not found"}}}},"/polymarket/market":{"get":{"tags":["Market"],"summary":"Get markets","description":"Retrieve a paginated list of markets with filtering, sorting, and optional nested tags/events/metrics","operationId":"list_markets","parameters":[{"name":"condition_ids","in":"query","description":"Filter by condition ID(s) - comma-separated (max 50)","required":false,"schema":{"type":"string"}},{"name":"question_ids","in":"query","description":"Filter by question ID(s) - comma-separated (max 50)","required":false,"schema":{"type":"string"}},{"name":"market_ids","in":"query","description":"Filter by market ID(s) - comma-separated (max 50)","required":false,"schema":{"type":"string"}},{"name":"market_slugs","in":"query","description":"Filter by market slug(s) - comma-separated (max 50)","required":false,"schema":{"type":"string"}},{"name":"event_slugs","in":"query","description":"Filter by event slug(s) - comma-separated (max 50)","required":false,"schema":{"type":"string"}},{"name":"position_ids","in":"query","description":"Filter by position ID(s) - comma-separated (max 50)","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","description":"Search in title (3-100 characters)","required":false,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Filter by status: open, closed, or all (default: all)","required":false,"schema":{"$ref":"#/components/schemas/MarketStatus"}},{"name":"sort_by","in":"query","description":"Sort: volume, txns, unique_traders, liquidity, holders, end_time, start_time, created_time, relevance","required":false,"schema":{"$ref":"#/components/schemas/MarketSortBy"}},{"name":"sort_dir","in":"query","description":"Sort direction: asc, desc (default: desc)","required":false,"schema":{"$ref":"#/components/schemas/SortDirection"}},{"name":"timeframe","in":"query","description":"Metrics timeframe: 1m, 5m, 30m, 1h, 6h, 24h, 7d, 30d (default: 24h)","required":false,"schema":{"$ref":"#/components/schemas/MetricsTimeframe"}},{"name":"min_volume","in":"query","description":"Minimum total volume USD","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_volume","in":"query","description":"Maximum total volume USD","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_liquidity","in":"query","description":"Minimum liquidity USD","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_liquidity","in":"query","description":"Maximum liquidity USD","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_txns","in":"query","description":"Minimum transactions in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"max_txns","in":"query","description":"Maximum transactions in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"min_unique_traders","in":"query","description":"Minimum unique traders in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"max_unique_traders","in":"query","description":"Maximum unique traders in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"min_holders","in":"query","description":"Minimum total holders","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"max_holders","in":"query","description":"Maximum total holders","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"categories","in":"query","description":"Comma-separated category filters (max 50)","required":false,"schema":{"type":"string"}},{"name":"exclude_categories","in":"query","description":"Comma-separated categories to exclude","required":false,"schema":{"type":"string"}},{"name":"tags","in":"query","description":"Filter by tag(s) - comma-separated (max 50)","required":false,"schema":{"type":"string"}},{"name":"exclude_tags","in":"query","description":"Comma-separated tags to exclude","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Filter markets with end_time >= start_time (Unix timestamp)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"end_time","in":"query","description":"Filter markets with end_time <= end_time (Unix timestamp)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"include_tags","in":"query","description":"Include tags array (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_event","in":"query","description":"Include event object (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_metrics","in":"query","description":"Include all timeframe metrics (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key","required":false,"schema":{"type":"string"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of markets with metadata, outcomes, tags, event, and metrics. Response includes `pagination: { has_more, pagination_key }` for cursor-based pagination.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MarketResponse"}}}}},"400":{"description":"Bad request - validation error (search length, array limits, conflicting params)"}}}},"/polymarket/market/bonds":{"get":{"tags":["Bonds"],"summary":"Get bonds","description":"Retrieve a list of bond markets sorted by yield, filtered by probability and time to expiry","operationId":"get_bonds","parameters":[{"name":"min_probability","in":"query","description":"Minimum probability threshold (default: 0.85)","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_hours","in":"query","description":"Maximum hours until market end","required":false,"schema":{"type":"number","format":"double"}},{"name":"limit","in":"query","description":"Number of results (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor for pagination: end_date (unix epoch) of the last item from the previous page","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"List of bond markets sorted by yield","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BondMarket"}}}}}}}},"/polymarket/market/candlestick":{"get":{"tags":["Market"],"summary":"Get market candlesticks by condition_id","description":"Retrieve OHLCV candlestick data for a market by its condition_id","operationId":"get_market_candlestick","parameters":[{"name":"condition_id","in":"query","description":"Market condition ID (required)","required":true,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Candle interval: 1, 5, 15, 30, 60, 240, D, 1D","required":true,"schema":{"$ref":"#/components/schemas/CandlestickResolution"}},{"name":"count_back","in":"query","description":"Number of candles (max: 2500)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"from","in":"query","description":"Start timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"OHLCV candlestick data","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PredictionCandlestickBar"}}}}}}}},"/polymarket/market/chart":{"get":{"tags":["Market"],"summary":"Get market chart","description":"Retrieve price data over time for up to 4 position outcomes in a market condition. TradingView-style: resolution parameter determines both candle size and implicit lookback period. Auto-selects the 4 most active outcomes if position_ids not specified.","operationId":"get_chart","parameters":[{"name":"condition_id","in":"query","description":"Market condition ID or market_slug (one required)","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (alternative to condition_id)","required":false,"schema":{"type":"string"}},{"name":"position_ids","in":"query","description":"Comma-separated list of position IDs (max 4, optional). Auto-selected if not provided","required":false,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Time interval with implicit lookback: 1H (1 hour), 6H (6 hours), 1D (1 day), 1W (1 week), 1M (30 days), ALL (all data) (required)","required":true,"schema":{"type":"string","enum":["1H","6H","1D","1W","1M","ALL"]}}],"responses":{"200":{"description":"Price data over time for up to 4 market outcomes","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PositionChartOutcome"}}}}}}}},"/polymarket/market/metrics":{"get":{"tags":["Market"],"summary":"Get market metrics","description":"Retrieve volume, transaction, and trader metrics for a market. Supports single timeframe (e.g., '1m'), multiple timeframes (e.g., '1m,5m,1h'), or 'all' to get all available timeframes.","operationId":"get_market_metrics","parameters":[{"name":"condition_id","in":"query","description":"Market condition ID","required":true,"schema":{"type":"string"}},{"name":"timeframe","in":"query","description":"Timeframe: single (1m, 5m, 30m, 1h, 6h, 24h, 7d, 30d), comma-separated (1m,5m,1h), or 'all'","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Market metrics for the specified timeframe(s). Returns single object for one timeframe, array for multiple.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConditionMetricsResponse"}}}},"400":{"description":"Invalid timeframe"}}}},"/polymarket/market/position/candlestick":{"get":{"tags":["Market"],"summary":"Get position candlesticks by position_id","description":"Retrieve OHLCV candlestick data for a specific position by its position_id","operationId":"get_position_candlestick","parameters":[{"name":"position_id","in":"query","description":"Position/token ID (required)","required":true,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Candle interval: 1, 5, 15, 30, 60, 240, D, 1D","required":true,"schema":{"$ref":"#/components/schemas/CandlestickResolution"}},{"name":"count_back","in":"query","description":"Number of candles (max: 2500)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"from","in":"query","description":"Start timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"OHLCV candlestick data","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PredictionCandlestickBar"}}}}}}}},"/polymarket/market/position/metrics":{"get":{"tags":["Market"],"summary":"Get position metrics","description":"Retrieve volume, transaction, and trader metrics for a specific position. Supports single timeframe (e.g., '1m'), multiple timeframes (e.g., '1m,5m,1h'), or 'all' to get all available timeframes.","operationId":"get_position_metrics","parameters":[{"name":"position_id","in":"query","description":"Position/token ID","required":true,"schema":{"type":"string"}},{"name":"timeframe","in":"query","description":"Timeframe: single (1m, 5m, 30m, 1h, 6h, 24h, 7d, 30d), comma-separated (1m,5m,1h), or 'all'","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Position metrics for the specified timeframe(s). Returns single object for one timeframe, array for multiple.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PositionMetricsResponse"}}}},"400":{"description":"Invalid timeframe"}}}},"/polymarket/market/position/volume-chart":{"get":{"tags":["Market"],"summary":"Get position volume chart","description":"Retrieve volume over time for a specific position with buy/sell breakdown","operationId":"get_position_volume_chart","parameters":[{"name":"position_id","in":"query","description":"Position/token ID (required)","required":true,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Time interval: 1, 5, 15, 30, 60, 240, D, 1D (default: 60)","required":false,"schema":{"$ref":"#/components/schemas/CandlestickResolution"}},{"name":"count_back","in":"query","description":"Number of data points (max: 2500)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"from","in":"query","description":"Start timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Volume with buy/sell breakdown over time","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PositionVolumeDataPoint"}}}}}}}},"/polymarket/market/price-jumps":{"get":{"tags":["Market"],"summary":"Detect price jumps","description":"Scan candles for significant price movements. Returns jumps with from/to timestamps in milliseconds, directly usable as trades API time range parameters to identify traders who traded before or during the movement.","operationId":"get_price_jumps","parameters":[{"name":"condition_id","in":"query","description":"Market condition ID (one of condition_id or market_slug required)","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (resolved to condition_id)","required":false,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Candle resolution in minutes: 1, 5, 15, 30, 60, 240 (default: 15)","required":false,"schema":{"type":"string"}},{"name":"min_change_pct","in":"query","description":"Minimum relative percent change to qualify as a jump (default: 10.0)","required":false,"schema":{"type":"number","format":"double"}},{"name":"lookback","in":"query","description":"Number of candles to scan back from now (default: 1440, max: 2500)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"offset","in":"query","description":"Offset in candles from now — window is [now - (lookback + offset) * resolution, now - offset * resolution] (default: 0)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Price jumps sorted by timestamp descending","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PriceJump"}}}}}}}},"/polymarket/market/slug/{slug}":{"get":{"tags":["Market"],"summary":"Get market by slug","description":"Retrieve a single market by its slug with optional nested tags, event, and metrics","operationId":"get_market_by_slug","parameters":[{"name":"slug","in":"path","description":"Market slug (e.g. `will-trump-win`)","required":true,"schema":{"type":"string"}},{"name":"include_tags","in":"query","description":"Include tags array (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_event","in":"query","description":"Include event object (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_metrics","in":"query","description":"Include all timeframe metrics (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Market with metadata, outcomes, tags, event, and metrics","content":{"application/json":{"schema":{"type":"object","description":"Formatted market response with structured metrics, tags, outcomes, and event","required":["condition_id","status"],"properties":{"condition_id":{"type":"string"},"id":{"type":["string","null"]},"market_slug":{"type":["string","null"]},"question":{"type":["string","null"]},"title":{"type":["string","null"]},"description":{"type":["string","null"]},"image_url":{"type":["string","null"]},"oracle":{"type":["string","null"]},"status":{"type":"string"},"created_time":{"type":["integer","null"],"format":"int64"},"start_time":{"type":["integer","null"],"format":"int64"},"game_start_time":{"type":["integer","null"],"format":"int64"},"closed_time":{"type":["integer","null"],"format":"int64"},"end_time":{"type":["integer","null"],"format":"int64"},"accepting_orders":{"type":["boolean","null"]},"uma_resolution_status":{"type":["string","null"]},"is_neg_risk":{"type":["boolean","null"]},"market_maker_address":{"type":["string","null"]},"creator":{"type":["string","null"]},"category":{"type":["string","null"]},"volume_usd":{"type":["number","null"],"format":"double"},"liquidity_usd":{"type":["number","null"],"format":"double"},"highest_probability":{"type":["number","null"],"format":"double"},"total_holders":{"type":["integer","null"],"format":"int64"},"winning_outcome":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/MarketOutcome"}]},"outcomes":{"type":"array","items":{"$ref":"#/components/schemas/MarketOutcome"}},"rewards":{"type":"array","items":{"$ref":"#/components/schemas/MarketReward"}},"clob_rewards":{"type":"array","items":{"$ref":"#/components/schemas/ClobReward"}},"tags":{"type":"array","items":{"type":"string"}},"event_slug":{"type":["string","null"]},"resolution_source":{"type":["string","null"]},"metrics":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/SimpleTimeframeMetrics"},"propertyNames":{"type":"string"}},"relevance_score":{"type":["number","null"],"format":"double"}}}}}},"404":{"description":"Market not found"}}}},"/polymarket/market/trades":{"get":{"tags":["Market"],"summary":"Get market trades","description":"Retrieve trades for one or more markets, with filtering by trader, side, price, amount, and time range","operationId":"get_market_trades","parameters":[{"name":"condition_ids","in":"query","description":"Comma-separated condition IDs (max 20)","required":false,"schema":{"type":"string"}},{"name":"slugs","in":"query","description":"Comma-separated market slugs","required":false,"schema":{"type":"string"}},{"name":"position_ids","in":"query","description":"Comma-separated position IDs","required":false,"schema":{"type":"string"}},{"name":"traders","in":"query","description":"Comma-separated trader addresses (max 25)","required":false,"schema":{"type":"string"}},{"name":"side","in":"query","description":"Trade side: 0 (Buy), 1 (Sell)","required":false,"schema":{"$ref":"#/components/schemas/TradeSide"}},{"name":"outcome","in":"query","description":"Outcome name filter (e.g. Yes, No)","required":false,"schema":{"type":"string"}},{"name":"outcome_index","in":"query","description":"Outcome index: 0 (Yes), 1 (No)","required":false,"schema":{"$ref":"#/components/schemas/OutcomeIndex"}},{"name":"trade_type","in":"query","description":"Trade type: 0 (OrderFilled), 1 (Redemption), 2 (Merge)","required":false,"schema":{"$ref":"#/components/schemas/TradeType"}},{"name":"min_usd_amount","in":"query","description":"Min USD amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_usd_amount","in":"query","description":"Max USD amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_shares_amount","in":"query","description":"Min shares amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_shares_amount","in":"query","description":"Max shares amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_price","in":"query","description":"Min price (0.0-1.0)","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_price","in":"query","description":"Max price (0.0-1.0)","required":false,"schema":{"type":"number","format":"double"}},{"name":"from","in":"query","description":"Start timestamp (ms)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (ms)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"all","in":"query","description":"Return all-time trades, not just last 30 days (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Results per page (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32","minimum":0}},{"name":"pagination_key","in":"query","description":"Offset-based pagination key (integer offset into result set)","required":false,"schema":{"type":"integer","format":"int32","minimum":0}},{"name":"sort_desc","in":"query","description":"Sort newest first (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Prediction trades matching filters","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PredictionTradeResponse"}}}}}}}},"/polymarket/market/volume-chart":{"get":{"tags":["Market"],"summary":"Get market volume chart","description":"Retrieve volume breakdown by YES/NO outcome over time for a prediction market","operationId":"get_market_volume_chart","parameters":[{"name":"condition_id","in":"query","description":"Market condition ID (or use market_slug)","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (alternative to condition_id)","required":false,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Time interval: 1, 5, 15, 30, 60, 240, D, 1D (default: 60)","required":false,"schema":{"$ref":"#/components/schemas/CandlestickResolution"}},{"name":"count_back","in":"query","description":"Number of data points (max: 2500)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"from","in":"query","description":"Start timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Volume breakdown by YES/NO over time","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MarketVolumeDataPoint"}}}}}}}},"/polymarket/market/{condition_id}":{"get":{"tags":["Market"],"summary":"Get market by condition ID","description":"Retrieve a single market by its condition ID with optional nested tags, event, and metrics","operationId":"get_market","parameters":[{"name":"condition_id","in":"path","description":"Market condition ID (0x-prefixed hex)","required":true,"schema":{"type":"string"}},{"name":"include_tags","in":"query","description":"Include tags array (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_event","in":"query","description":"Include event object (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_metrics","in":"query","description":"Include all timeframe metrics (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Market with metadata, outcomes, tags, event, and metrics","content":{"application/json":{"schema":{"type":"object","description":"Formatted market response with structured metrics, tags, outcomes, and event","required":["condition_id","status"],"properties":{"condition_id":{"type":"string"},"id":{"type":["string","null"]},"market_slug":{"type":["string","null"]},"question":{"type":["string","null"]},"title":{"type":["string","null"]},"description":{"type":["string","null"]},"image_url":{"type":["string","null"]},"oracle":{"type":["string","null"]},"status":{"type":"string"},"created_time":{"type":["integer","null"],"format":"int64"},"start_time":{"type":["integer","null"],"format":"int64"},"game_start_time":{"type":["integer","null"],"format":"int64"},"closed_time":{"type":["integer","null"],"format":"int64"},"end_time":{"type":["integer","null"],"format":"int64"},"accepting_orders":{"type":["boolean","null"]},"uma_resolution_status":{"type":["string","null"]},"is_neg_risk":{"type":["boolean","null"]},"market_maker_address":{"type":["string","null"]},"creator":{"type":["string","null"]},"category":{"type":["string","null"]},"volume_usd":{"type":["number","null"],"format":"double"},"liquidity_usd":{"type":["number","null"],"format":"double"},"highest_probability":{"type":["number","null"],"format":"double"},"total_holders":{"type":["integer","null"],"format":"int64"},"winning_outcome":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/MarketOutcome"}]},"outcomes":{"type":"array","items":{"$ref":"#/components/schemas/MarketOutcome"}},"rewards":{"type":"array","items":{"$ref":"#/components/schemas/MarketReward"}},"clob_rewards":{"type":"array","items":{"$ref":"#/components/schemas/ClobReward"}},"tags":{"type":"array","items":{"type":"string"}},"event_slug":{"type":["string","null"]},"resolution_source":{"type":["string","null"]},"metrics":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/SimpleTimeframeMetrics"},"propertyNames":{"type":"string"}},"relevance_score":{"type":["number","null"],"format":"double"}}}}}},"404":{"description":"Market not found"}}}},"/polymarket/order-book":{"get":{"tags":["Order Book"],"summary":"Get order book","description":"Returns the latest CLOB orderbook snapshot for a position, including derived metrics (best bid/ask, mid price, spread, liquidity depth). Data is sourced from the real-time Polymarket WebSocket feed. `bids` and `asks` are arrays of `{\"p\": price, \"s\": size}` objects, sorted best-first.","operationId":"get_order_book","parameters":[{"name":"position_id","in":"query","description":"Token ID (position ID) to query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Latest orderbook snapshot. ts is Unix milliseconds.","content":{"application/json":{"schema":{"type":"object","required":["ts","position_id","condition_id","bids","asks","hash"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"bids":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"asks":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"hash":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}}}}},"400":{"description":"Missing or invalid parameters"}}}},"/polymarket/order-book/history":{"get":{"tags":["Order Book"],"summary":"Get order book history","description":"Paginated history of raw CLOB orderbook snapshots including full bids/asks levels and derived metrics. Default limit 20, max 200. `bids` and `asks` are arrays of `{\"p\": price, \"s\": size}` objects, sorted best-first.","operationId":"get_order_book_history","parameters":[{"name":"position_id","in":"query","description":"Token ID (required if condition_id / market_slug not set)","required":false,"schema":{"type":"string"}},{"name":"condition_id","in":"query","description":"Condition ID — returns history for all positions in this market","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (alternative to condition_id)","required":false,"schema":{"type":"string"}},{"name":"from","in":"query","description":"Start timestamp (Unix milliseconds, inclusive)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (Unix milliseconds, inclusive)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"min_spread","in":"query","description":"Only return snapshots with spread >= this value","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_spread","in":"query","description":"Only return snapshots with spread <= this value","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_liquidity","in":"query","description":"Only return snapshots where total liquidity (bid + ask) >= this value","required":false,"schema":{"type":"number","format":"double"}},{"name":"limit","in":"query","description":"Number of results (default: 20, max: 200)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"pagination_key","in":"query","description":"Cursor from previous response's pagination.pagination_key","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Orderbook snapshot rows, newest first. ts is Unix milliseconds.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","required":["ts","position_id","condition_id","bids","asks","hash"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"bids":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"asks":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"hash":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}}}}}},"400":{"description":"Missing or invalid parameters"}}}},"/polymarket/order-book/market":{"get":{"tags":["Order Book"],"summary":"Get order books for a market","description":"Returns the latest orderbook snapshot for every position (outcome) in a market. Accepts condition_id or market_slug. `bids` and `asks` are arrays of `{\"p\": price, \"s\": size}` objects, sorted best-first.","operationId":"get_market_order_book","parameters":[{"name":"condition_id","in":"query","description":"Condition ID of the market","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (alternative to condition_id)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Latest orderbook snapshot per position. ts is Unix milliseconds.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","required":["ts","position_id","condition_id","bids","asks","hash"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"bids":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"asks":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"hash":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}}}}}},"400":{"description":"Missing or invalid parameters"}}}},"/polymarket/order-book/spread":{"get":{"tags":["Order Book"],"summary":"Get spread history","description":"Lightweight time series of derived orderbook metrics (best bid/ask, mid price, spread, liquidity depth) without raw bids/asks — ideal for charting. Default limit 20, max 200.","operationId":"get_spread_history","parameters":[{"name":"position_id","in":"query","description":"Token ID (required if condition_id / market_slug not set)","required":false,"schema":{"type":"string"}},{"name":"condition_id","in":"query","description":"Condition ID — returns spread history for all positions in this market","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (alternative to condition_id)","required":false,"schema":{"type":"string"}},{"name":"from","in":"query","description":"Start timestamp (Unix milliseconds, inclusive)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (Unix milliseconds, inclusive)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"min_spread","in":"query","description":"Only return rows with spread >= this value","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_spread","in":"query","description":"Only return rows with spread <= this value","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_liquidity","in":"query","description":"Only return rows where total liquidity (bid + ask) >= this value","required":false,"schema":{"type":"number","format":"double"}},{"name":"limit","in":"query","description":"Number of results (default: 100, max: 1000)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"pagination_key","in":"query","description":"Cursor from previous response's pagination.pagination_key","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Spread time series rows, newest first. ts is Unix milliseconds.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","description":"Lightweight row — derived metrics only, no bids/asks JSONB.","required":["ts","position_id","condition_id"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}}}}}},"400":{"description":"Missing or invalid parameters"}}}},"/polymarket/search":{"get":{"tags":["Search"],"summary":"Search events, markets, and traders","description":"Search across markets, events, and traders. Use `type` to limit which categories are searched. Trader search supports wallet address lookup or name search. Results for each category are independently paginated. Only requested categories are included in the response.","operationId":"search","parameters":[{"name":"q","in":"query","description":"Search query (min 2 characters). Prefix with 0x for exact wallet address lookup.","required":true,"schema":{"type":"string"}},{"name":"type","in":"query","description":"Comma-separated categories to search: events, markets, traders (default: all three, 1 credit per type). Example: type=markets,traders","required":false,"schema":{"type":"string"}},{"name":"include_pnl","in":"query","description":"Include lifetime PnL summary for each trader (default: false, +1 credit)","required":false,"schema":{"type":"boolean"}},{"name":"sort_by","in":"query","description":"Sort field applied to both events and markets (default: volume). Fields marked events-only or markets-only fall back to volume on the other category.","required":false,"schema":{"$ref":"#/components/schemas/SearchSortBy"}},{"name":"sort_dir","in":"query","description":"Sort direction (default: desc)","required":false,"schema":{"$ref":"#/components/schemas/SortDirection"}},{"name":"timeframe","in":"query","description":"Metrics timeframe used for volume/txns/unique_traders sort (default: 24h)","required":false,"schema":{"$ref":"#/components/schemas/MetricsTimeframe"}},{"name":"limit","in":"query","description":"Results limit per category (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"events_pagination_key","in":"query","description":"Cursor for the next page of events, obtained from previous response's events_pagination.pagination_key","required":false,"schema":{"type":"string"}},{"name":"markets_pagination_key","in":"query","description":"Cursor for the next page of markets, obtained from previous response's markets_pagination.pagination_key","required":false,"schema":{"type":"string"}},{"name":"traders_pagination_key","in":"query","description":"Cursor for the next page of traders, obtained from previous response's traders_pagination.pagination_key","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Search results. Only requested categories (via `type`) are included in the response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchResponse"}}}},"400":{"description":"Bad request — q is missing or shorter than 2 characters"}}}},"/polymarket/series":{"get":{"tags":["Series"],"summary":"List or get series","description":"Retrieve series. Use `id` or `series_slug` for single lookup, `series_ids` or `series_slugs` (comma-separated, max 250, mutually exclusive) for multi-lookup, or paginate with `active_only`.","operationId":"get_series_list","parameters":[{"name":"id","in":"query","description":"Single series ID for direct lookup","required":false,"schema":{"type":"string"}},{"name":"series_ids","in":"query","description":"Comma-separated series IDs (max 250). Mutually exclusive with series_slugs.","required":false,"schema":{"type":"string"}},{"name":"series_slugs","in":"query","description":"Comma-separated series slugs (max 250). Mutually exclusive with series_ids.","required":false,"schema":{"type":"string"}},{"name":"active_only","in":"query","description":"Only active series (default: true). Ignored when series_ids or series_slugs are provided.","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor for pagination: id of the last series from the previous page","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Series or list of series","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PolymarketSeries"}}}}},"400":{"description":"series_ids and series_slugs cannot both be provided"}}}},"/polymarket/series/outcomes":{"get":{"tags":["Series"],"summary":"Get series market outcomes","description":"Returns the winning outcome name for each resolved market across all events in a series, keyed by market slug. Useful for checking historical results across recurring series (e.g., btc-updown-5m).","operationId":"get_series_outcomes","parameters":[{"name":"series_slug","in":"query","description":"Series slug (required)","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Number of resolved markets per page (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key for fetching next page","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Map of market_slug → winning outcome name with pagination metadata","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}}}}},"400":{"description":"Missing series_slug parameter"}}}},"/polymarket/tags":{"get":{"tags":["Tags"],"summary":"Get tags","description":"Retrieve all available event tags/categories. Uses cursor-based pagination for efficient traversal.","operationId":"get_tags","parameters":[{"name":"limit","in":"query","description":"Results limit (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of all tags","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PolymarketTag"}}}}}}}},"/polymarket/tags/{identifier}":{"get":{"tags":["Tags"],"summary":"Get tag by slug","description":"Retrieve a single tag by its ID or slug","operationId":"get_tag_by_id","parameters":[{"name":"identifier","in":"path","description":"Tag ID or slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Tag details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PolymarketTag"}}}},"404":{"description":"Tag not found"}}}},"/polymarket/trader/global_pnl":{"get":{"tags":["Trader"],"summary":"Get global leaderboard","description":"Retrieve the global PnL leaderboard ranked by profit and loss. Uses cursor-based pagination for efficient traversal of large datasets.","operationId":"get_global_pnl","parameters":[{"name":"timeframe","in":"query","description":"Timeframe: 1d, 7d, 30d, lifetime (default: lifetime)","required":false,"schema":{"$ref":"#/components/schemas/PnlTimeframe"}},{"name":"sort_by","in":"query","description":"Sort: realized_pnl_usd, buys, sells, redemptions, merges, avg_hold_time, markets_traded, events_traded, markets_won, volume_usd, fees, best_trade (default: realized_pnl_usd)","required":false,"schema":{"$ref":"#/components/schemas/GlobalPnlSortBy"}},{"name":"sort_direction","in":"query","description":"Sort direction: asc, desc (default: desc)","required":false,"schema":{"$ref":"#/components/schemas/SortDirection"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 200)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Global PnL leaderboard with trader stats. Response includes `pagination: { has_more, pagination_key }` for cursor-based pagination.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GlobalPnlTrader"}}}}}}}},"/polymarket/trader/pnl/{address}":{"get":{"tags":["Trader"],"summary":"Get trader PnL summary","description":"Retrieve a trader's overall profit and loss summary","operationId":"get_trader_pnl","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"timeframe","in":"query","description":"Timeframe: 1d, 7d, 30d, lifetime (default: lifetime)","required":false,"schema":{"$ref":"#/components/schemas/PnlTimeframe"}}],"responses":{"200":{"description":"Trader's global PnL summary","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TraderPnlSummary"}}}}}}},"/polymarket/trader/pnl/{address}/calendar":{"get":{"tags":["Trader"],"summary":"Get trader PnL calendar","description":"Retrieve raw per-day PnL. Each entry is the realized PnL for that calendar day. Paginate backwards using the pagination key.","operationId":"get_trader_pnl_calendar","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"days","in":"query","description":"Window size in days (default: 30, max: 30)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Pagination key obtained from a previous response to fetch an earlier window","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Daily PnL entries (one per active trading day)","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PnlCandleEntry"}}}}}}}},"/polymarket/trader/pnl/{address}/candles":{"get":{"tags":["Trader"],"summary":"Get trader PnL candles","description":"Retrieve PnL candles for charting a trader's equity curve over time.","operationId":"get_trader_pnl_candles","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Candle resolution (default: 1h)","required":false,"schema":{"$ref":"#/components/schemas/PnlCandleResolution"}},{"name":"timeframe","in":"query","description":"Time range (default: lifetime)","required":false,"schema":{"$ref":"#/components/schemas/PnlCandleTimeframe"}}],"responses":{"200":{"description":"Cumulative PnL candles","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PnlCandleEntry"}}}}}}}},"/polymarket/trader/pnl/{address}/events":{"get":{"tags":["Trader"],"summary":"Get trader event PnL","description":"Retrieve event-level PnL breakdown for a trader","operationId":"get_trader_event_pnl","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"timeframe","in":"query","description":"Timeframe: 1d, 7d, 30d, lifetime (default: lifetime)","required":false,"schema":{"$ref":"#/components/schemas/PnlTimeframe"}},{"name":"sort_by","in":"query","description":"Sort: realized_pnl_usd, total_volume_usd, markets_traded, total_fees (default: realized_pnl_usd)","required":false,"schema":{"$ref":"#/components/schemas/EventPnlSortBy"}},{"name":"sort_direction","in":"query","description":"Sort direction: asc, desc (default: desc)","required":false,"schema":{"$ref":"#/components/schemas/SortDirection"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 200)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"offset","in":"query","description":"Pagination offset (number of results to skip). Takes precedence over pagination_key.","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key obtained from previous response's pagination.pagination_key","required":false,"schema":{"type":"string"}},{"name":"event_slug","in":"query","description":"Filter by event slug","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Event-level PnL entries for this trader","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TraderEventPnlEntry"}}}}}}}},"/polymarket/trader/pnl/{address}/markets":{"get":{"tags":["Trader"],"summary":"Get trader market PnL","description":"Retrieve market-level PnL breakdown for a trader","operationId":"get_trader_market_pnl","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"timeframe","in":"query","description":"Timeframe: 1d, 7d, 30d, lifetime (default: lifetime)","required":false,"schema":{"$ref":"#/components/schemas/PnlTimeframe"}},{"name":"sort_by","in":"query","description":"Sort: realized_pnl_usd, buy_usd, total_buys, total_fees, outcomes_traded (default: realized_pnl_usd)","required":false,"schema":{"$ref":"#/components/schemas/MarketPnlSortBy"}},{"name":"sort_direction","in":"query","description":"Sort direction: asc, desc (default: desc)","required":false,"schema":{"$ref":"#/components/schemas/SortDirection"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 200)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"offset","in":"query","description":"Pagination offset (number of results to skip). Takes precedence over pagination_key.","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key obtained from previous response's pagination.pagination_key","required":false,"schema":{"type":"string"}},{"name":"condition_id","in":"query","description":"Filter by condition ID (or use market_slug)","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Filter by market slug (alternative to condition_id)","required":false,"schema":{"type":"string"}},{"name":"event_slug","in":"query","description":"Filter by event slug","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Market-level PnL entries for this trader","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TraderMarketPnlEntry"}}}}}}}},"/polymarket/trader/pnl/{address}/positions":{"get":{"tags":["Trader"],"summary":"Get trader position PnL","description":"Retrieve per-outcome-token lifetime PnL for a trader from polymarket_accounts. Includes open/closed state, win/loss outcome, redemption payouts, and share quantities. Filter by status and won/lost to segment portfolio views.","operationId":"get_trader_position_pnl","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Required. Filter by position status","required":true,"schema":{"type":"string","enum":["open","closed"]}},{"name":"won","in":"query","description":"Filter by outcome: true (won), false (lost), only for status=closed","required":false,"schema":{"type":"boolean"}},{"name":"search","in":"query","description":"Search by market title","required":false,"schema":{"type":"string"}},{"name":"sort_by","in":"query","description":"Sort field (default: realized_pnl_usd)","required":false,"schema":{"$ref":"#/components/schemas/PositionPnlSortBy"}},{"name":"sort_direction","in":"query","description":"Sort direction: asc, desc (default: desc)","required":false,"schema":{"$ref":"#/components/schemas/SortDirection"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 200)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"offset","in":"query","description":"Pagination offset","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"condition_id","in":"query","description":"Filter by market condition ID (or use market_slug)","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Filter by market slug (alternative to condition_id)","required":false,"schema":{"type":"string"}},{"name":"position_id","in":"query","description":"Filter by specific outcome token (position ID)","required":false,"schema":{"type":"string"}},{"name":"min_shares","in":"query","description":"Minimum shares balance to include (e.g. 1.0 to filter out dust positions)","required":false,"schema":{"type":"number","format":"double"}}],"responses":{"200":{"description":"Position-level PnL entries for this trader. Each entry is a specific outcome token with open/closed state, avg_entry_price, avg_exit_price, and redemption info.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TraderOutcomePnlEntry"}}}}}}}},"/polymarket/trader/profile/{address}":{"get":{"tags":["Trader"],"summary":"Get trader overview","description":"Retrieve a trader's profile including stats and trading history summary","operationId":"get_trader_profile","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Trader profile information with username, bio, and badges","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PolymarketUserProfile"}}}}}}},"/polymarket/trader/profiles/batch":{"get":{"tags":["Trader"],"summary":"Get multiple trader profiles","description":"Retrieve profiles for multiple traders in a single request. Returns an array of profiles.","operationId":"get_trader_profiles_batch","parameters":[{"name":"addresses","in":"query","description":"Comma-separated list of trader addresses (max: 20)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Array of trader profiles","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PolymarketUserProfile"}}}}},"400":{"description":"Invalid request (empty addresses or more than 20)"}}}},"/polymarket/trader/trades/{address}":{"get":{"tags":["Trader"],"summary":"Get trader trades","description":"Retrieve trade history for a specific trader across all markets","operationId":"get_trader_trades","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"condition_ids","in":"query","description":"Comma-separated condition IDs (max 20)","required":false,"schema":{"type":"string"}},{"name":"slugs","in":"query","description":"Comma-separated market slugs","required":false,"schema":{"type":"string"}},{"name":"position_ids","in":"query","description":"Comma-separated position IDs","required":false,"schema":{"type":"string"}},{"name":"side","in":"query","description":"Trade side: 0 (Buy), 1 (Sell)","required":false,"schema":{"$ref":"#/components/schemas/TradeSide"}},{"name":"outcome","in":"query","description":"Outcome name filter (e.g. Yes, No)","required":false,"schema":{"type":"string"}},{"name":"outcome_index","in":"query","description":"Outcome index: 0 (Yes), 1 (No)","required":false,"schema":{"$ref":"#/components/schemas/OutcomeIndex"}},{"name":"trade_type","in":"query","description":"Trade type: 0 (OrderFilled), 1 (Redemption), 2 (Merge)","required":false,"schema":{"$ref":"#/components/schemas/TradeType"}},{"name":"min_usd_amount","in":"query","description":"Min USD amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_usd_amount","in":"query","description":"Max USD amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_shares_amount","in":"query","description":"Min shares amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_shares_amount","in":"query","description":"Max shares amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_price","in":"query","description":"Min price (0.0-1.0)","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_price","in":"query","description":"Max price (0.0-1.0)","required":false,"schema":{"type":"number","format":"double"}},{"name":"from","in":"query","description":"Start timestamp (ms)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (ms)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"all","in":"query","description":"Return all-time trades, not just last 30 days (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Results per page (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32","minimum":0}},{"name":"offset","in":"query","description":"Pagination offset (number of results to skip). Takes precedence over pagination_key.","required":false,"schema":{"type":"integer","format":"int32","minimum":0}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key obtained from previous response's pagination.pagination_key","required":false,"schema":{"type":"string"}},{"name":"sort_desc","in":"query","description":"Sort newest first (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Trader's trade history with advanced filtering (same as /market/trades but filtered by trader)","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PredictionTradeResponse"}}}}}}}},"/polymarket/trader/volume-chart/{address}":{"get":{"tags":["Trader"],"summary":"Get trader volume chart","description":"Retrieve volume breakdown by buy/sell over time for a specific trader","operationId":"get_trader_volume_chart","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Time interval: 1, 5, 15, 30, 60, 240, D, 1D (default: 60)","required":false,"schema":{"$ref":"#/components/schemas/CandlestickResolution"}},{"name":"count_back","in":"query","description":"Number of data points (max: 2500)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"from","in":"query","description":"Start timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Trader volume with buy/sell breakdown over time","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TraderVolumeDataPoint"}}}}}}}}},"components":{"schemas":{"AssetPriceHistoryRow":{"type":"object","description":"A single asset price history record from the `asset_price_history` table.","required":["asset_symbol","asset_open_price","asset_close_price","variant","start_time","end_time"],"properties":{"asset_symbol":{"type":"string"},"asset_open_price":{"type":"number","format":"double","description":"Opening price at start_time (cast to f64 from NUMERIC in query)"},"asset_close_price":{"type":"number","format":"double","description":"Closing price at end_time (cast to f64 from NUMERIC in query)"},"price_change_percentage":{"type":["number","null"],"format":"double"},"outcome":{"type":["string","null"],"description":"Generated column: \"up\" if close > open, \"down\" if close ≤ open, null if no close yet"},"variant":{"type":"string","description":"Time window: \"5m\", \"15m\", \"1h\", \"1d\""},"start_time":{"type":"integer","format":"int64","description":"Window start timestamp (seconds since epoch)"},"end_time":{"type":"integer","format":"int64","description":"Window end timestamp (seconds since epoch)"}}},"AssetSymbol":{"type":"string","enum":["BTC","ETH","XRP","SOL","DOGE","BNB","HYPE"]},"AssetVariant":{"type":"string","enum":["5m","15m","1h","4h","1d"]},"BondMarket":{"type":"object","required":["condition_id","question","market_slug","end_time","best_outcome_index","return_pct","apy","outcomes"],"properties":{"condition_id":{"type":"string"},"title":{"type":["string","null"]},"question":{"type":"string"},"market_slug":{"type":"string"},"event_slug":{"type":["string","null"]},"image_url":{"type":["string","null"]},"end_time":{"type":"integer","format":"int64"},"best_outcome_index":{"type":"integer","format":"int32","minimum":0},"return_pct":{"type":"number","format":"double"},"apy":{"type":"number","format":"double"},"volume_24h":{"type":["number","null"],"format":"double"},"outcomes":{"type":"array","items":{"$ref":"#/components/schemas/BondOutcome"}}}},"BondOutcome":{"type":"object","required":["name","index","position_id","price"],"properties":{"name":{"type":"string"},"index":{"type":"integer","format":"int32"},"position_id":{"type":"string"},"price":{"type":"number","format":"double"}}},"CandlestickResolution":{"type":"string","enum":["1","5","15","30","60","240","D","1D"]},"ClobReward":{"type":"object","description":"CLOB reward (public API format)","required":["id","condition_id"],"properties":{"id":{"type":"string"},"condition_id":{"type":"string"},"asset_address":{"type":["string","null"]},"rewards_amount":{"type":["number","null"],"format":"double"},"rewards_daily_rate":{"type":["number","null"],"format":"double"},"start_date":{"type":["string","null"]},"end_date":{"type":["string","null"]}}},"ConditionMetricsResponse":{"type":"object","description":"Response type for condition metrics query","required":["condition_id","timeframe","volume_usd","fees","txns","unique_traders"],"properties":{"condition_id":{"type":"string"},"timeframe":{"type":"string"},"volume_usd":{"type":"number","format":"double"},"fees":{"type":"number","format":"double"},"txns":{"type":"integer","format":"int32"},"unique_traders":{"type":"integer","format":"int32"}}},"ConditionOrderbookRow":{"type":"object","required":["ts","position_id","condition_id","bids","asks","hash"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"bids":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"asks":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"hash":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}},"EventMarket":{"type":"object","description":"Enriched market data for event API responses","properties":{"condition_id":{"type":"string","default":""},"id":{"type":["string","null"],"default":null},"title":{"type":["string","null"],"default":null},"question":{"type":"string","default":""},"market_slug":{"type":"string","default":""},"status":{"type":"string","default":""},"created_time":{"type":["integer","null"],"format":"int64","default":null},"end_time":{"type":["integer","null"],"format":"int64","default":null},"volume":{"type":["number","null"],"format":"double","default":null},"liquidity_usd":{"type":["number","null"],"format":"double","default":null},"volume_24hr":{"type":["number","null"],"format":"double","default":null},"image_url":{"type":["string","null"],"default":null},"market_maker_address":{"type":["string","null"],"default":null},"creator":{"type":["string","null"],"default":null},"category":{"type":["string","null"],"default":null},"accepting_orders":{"type":["boolean","null"],"default":null},"uma_resolution_status":{"type":["string","null"],"default":null},"clob_rewards":{"type":"array","items":{"$ref":"#/components/schemas/ClobReward"},"default":[]},"outcomes":{"type":"array","items":{"$ref":"#/components/schemas/EventMarketOutcome"},"default":[]},"winning_outcome":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/EventMarketOutcome"}],"default":null}}},"EventMarketChartDataPoint":{"type":"object","required":["v","t"],"properties":{"v":{"type":"number","format":"double"},"t":{"type":"integer","format":"int64","minimum":0}}},"EventMarketChartOutcome":{"type":"object","required":["condition_id","market_slug","question","title","data"],"properties":{"condition_id":{"type":"string"},"market_slug":{"type":"string"},"question":{"type":"string"},"title":{"type":"string"},"data":{"type":"array","items":{"$ref":"#/components/schemas/EventMarketChartDataPoint"}}}},"EventMarketOutcome":{"type":"object","description":"Market outcome for event API responses","required":["name"],"properties":{"name":{"type":"string"},"price":{"type":["number","null"],"format":"double"},"position_id":{"type":["string","null"]},"outcome_index":{"type":["integer","null"],"format":"int32"}}},"EventMetricsResponse":{"type":"object","description":"Response type for event metrics query","required":["event_slug","timeframe","volume_usd","fees","txns","unique_traders"],"properties":{"event_slug":{"type":"string"},"timeframe":{"type":"string"},"volume_usd":{"type":"number","format":"double"},"fees":{"type":"number","format":"double"},"txns":{"type":"integer","format":"int32"},"unique_traders":{"type":"integer","format":"int32"}}},"EventPnlSortBy":{"type":"string","enum":["realized_pnl_usd","total_volume_usd","markets_traded","total_fees","realized_pnl_pct"]},"EventSortBy":{"type":"string","enum":["volume","txns","unique_traders","title","creation_date","start_date","end_date","relevance"]},"GlobalPnlSortBy":{"type":"string","enum":["realized_pnl_usd","buys","sells","redemptions","merges","avg_hold_time","markets_traded","events_traded","markets_won","volume_usd","fees","best_trade"]},"GlobalPnlTrader":{"type":"object","description":"Individual trader entry in the global PnL leaderboard","required":["trader"],"properties":{"trader":{"$ref":"#/components/schemas/TraderInfo"},"realized_pnl_usd":{"type":["number","null"],"format":"double"},"events_traded":{"type":["integer","null"],"format":"int64"},"markets_traded":{"type":["integer","null"],"format":"int64"},"markets_won":{"type":["integer","null"],"format":"int64"},"markets_lost":{"type":["integer","null"],"format":"int64"},"market_win_rate_pct":{"type":["number","null"],"format":"double"},"total_volume_usd":{"type":["number","null"],"format":"double"},"buy_volume_usd":{"type":["number","null"],"format":"double"},"sell_volume_usd":{"type":["number","null"],"format":"double"},"redemption_volume_usd":{"type":["number","null"],"format":"double"},"merge_volume_usd":{"type":["number","null"],"format":"double"},"total_buys":{"type":["integer","null"],"format":"int64"},"total_sells":{"type":["integer","null"],"format":"int64"},"total_redemptions":{"type":["integer","null"],"format":"int64"},"total_merges":{"type":["integer","null"],"format":"int64"},"total_trades":{"type":["integer","null"],"format":"int64"},"total_fees":{"type":["number","null"],"format":"double"},"avg_pnl_per_market":{"type":["number","null"],"format":"double"},"avg_pnl_per_trade":{"type":["number","null"],"format":"double"},"avg_hold_time_seconds":{"type":["number","null"],"format":"double"},"best_trade_pnl_usd":{"type":["number","null"],"format":"double"},"best_trade_condition_id":{"type":["string","null"]},"first_trade_at":{"type":["integer","null"],"format":"int64"},"last_trade_at":{"type":["integer","null"],"format":"int64"}}},"Holder":{"type":"object","description":"Individual holder data","required":["trader","shares"],"properties":{"trader":{"$ref":"#/components/schemas/Trader","description":"Trader profile information"},"shares":{"type":"string","description":"Position shares held (raw balance as string for precision)"},"shares_usd":{"type":["string","null"],"description":"USD value of shares (shares * latest price)"},"usd_balance":{"type":["string","null"],"description":"USD balance of wallet (USDe on Polygon)"},"pnl":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/HolderPnl","description":"Holder-level PnL, included only when `include_pnl=true`"}]}}},"HolderHistoryCandle":{"type":"object","description":"Holder statistics data point (single time bucket)","required":["t"],"properties":{"t":{"type":"integer","format":"int64"},"h":{"type":["integer","null"],"format":"int64"}}},"HolderPnl":{"type":"object","description":"Holder-level PnL data, included when `include_pnl=true`","properties":{"avg_entry_price":{"type":["number","null"],"format":"double"},"total_cost_usd":{"type":["string","null"]},"unrealized_pnl_usd":{"type":["string","null"]},"realized_sell_pnl_usd":{"type":["string","null"]},"avg_exit_price":{"type":["number","null"],"format":"double"},"buy_usd":{"type":["number","null"],"format":"double"},"sell_usd":{"type":["number","null"],"format":"double"},"total_buys":{"type":["integer","null"],"format":"int64"},"total_sells":{"type":["integer","null"],"format":"int64"},"total_fees":{"type":["number","null"],"format":"double"},"first_trade_at":{"type":["integer","null"],"format":"int64"},"last_trade_at":{"type":["integer","null"],"format":"int64"}}},"MarketHoldersResponse":{"type":"object","description":"Response for market (condition_id) holders endpoint","required":["condition_id","total_holders","outcomes"],"properties":{"condition_id":{"type":"string","description":"Market condition ID"},"question":{"type":["string","null"],"description":"Market question/title"},"slug":{"type":["string","null"],"description":"Market slug"},"total_holders":{"type":"integer","format":"int64","description":"Total unique holders across all outcomes (from holder_stats)"},"outcomes":{"type":"array","items":{"$ref":"#/components/schemas/OutcomeHolders"},"description":"Holders grouped by outcome"}}},"MarketMetadata":{"type":"object","description":"Market metadata (enriched, cached version)","required":["condition_id","question","description","slug","neg_risk","tokens","tags","outcomes","metrics","clob_rewards"],"properties":{"condition_id":{"type":"string"},"question":{"type":"string"},"description":{"type":"string"},"slug":{"type":"string"},"event_slug":{"type":["string","null"]},"event_id":{"type":["string","null"]},"event_title":{"type":["string","null"]},"series_slug":{"type":["string","null"]},"neg_risk":{"type":"boolean"},"tokens":{"type":"array","items":{"$ref":"#/components/schemas/TokenOutcome"}},"image_url":{"type":["string","null"]},"tags":{"type":"array","items":{"type":"string"}},"created_time":{"type":["integer","null"],"format":"int64"},"start_time":{"type":["integer","null"],"format":"int64"},"game_start_time":{"type":["integer","null"],"format":"int64"},"closed_time":{"type":["integer","null"],"format":"int64"},"end_time":{"type":["integer","null"],"format":"int64"},"title":{"type":["string","null"]},"id":{"type":["string","null"]},"volume_usd":{"type":["number","null"],"format":"double"},"liquidity_usd":{"type":["number","null"],"format":"double"},"outcomes":{"type":"array","items":{"$ref":"#/components/schemas/MarketOutcome"}},"metrics":{"type":"object","additionalProperties":{"type":"number","format":"double"},"propertyNames":{"type":"string"}},"market_maker_address":{"type":["string","null"]},"creator":{"type":["string","null"]},"category":{"type":["string","null"]},"clob_rewards":{"type":"array","items":{"$ref":"#/components/schemas/ClobReward"}}}},"MarketMetadataOutcome":{"type":"object","description":"Market outcome with timeframe metrics (websocket API format)","required":["token_id","outcome"],"properties":{"token_id":{"type":"string"},"outcome":{"type":"string"},"last_price":{"type":["number","null"],"format":"double"},"last_probability":{"type":["number","null"],"format":"double"},"metrics":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/OutcomeTimeframeMetrics"},"propertyNames":{"type":"string"}}}},"MarketOutcome":{"type":"object","description":"Outcome for market API responses","properties":{"name":{"type":"string","default":""},"price":{"type":["number","null"],"format":"double","default":null},"position_id":{"type":["string","null"],"default":null},"outcome_index":{"type":["integer","null"],"format":"int32","default":null}}},"MarketPnlSortBy":{"type":"string","enum":["realized_pnl_usd","buy_usd","total_buys","total_fees","outcomes_traded","realized_pnl_pct"]},"MarketResponse":{"type":"object","description":"Formatted market response with structured metrics, tags, outcomes, and event","required":["condition_id","status"],"properties":{"condition_id":{"type":"string"},"id":{"type":["string","null"]},"market_slug":{"type":["string","null"]},"question":{"type":["string","null"]},"title":{"type":["string","null"]},"description":{"type":["string","null"]},"image_url":{"type":["string","null"]},"oracle":{"type":["string","null"]},"status":{"type":"string"},"created_time":{"type":["integer","null"],"format":"int64"},"start_time":{"type":["integer","null"],"format":"int64"},"game_start_time":{"type":["integer","null"],"format":"int64"},"closed_time":{"type":["integer","null"],"format":"int64"},"end_time":{"type":["integer","null"],"format":"int64"},"accepting_orders":{"type":["boolean","null"]},"uma_resolution_status":{"type":["string","null"]},"is_neg_risk":{"type":["boolean","null"]},"market_maker_address":{"type":["string","null"]},"creator":{"type":["string","null"]},"category":{"type":["string","null"]},"volume_usd":{"type":["number","null"],"format":"double"},"liquidity_usd":{"type":["number","null"],"format":"double"},"highest_probability":{"type":["number","null"],"format":"double"},"total_holders":{"type":["integer","null"],"format":"int64"},"winning_outcome":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/MarketOutcome"}]},"outcomes":{"type":"array","items":{"$ref":"#/components/schemas/MarketOutcome"}},"rewards":{"type":"array","items":{"$ref":"#/components/schemas/MarketReward"}},"clob_rewards":{"type":"array","items":{"$ref":"#/components/schemas/ClobReward"}},"tags":{"type":"array","items":{"type":"string"}},"event_slug":{"type":["string","null"]},"resolution_source":{"type":["string","null"]},"metrics":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/SimpleTimeframeMetrics"},"propertyNames":{"type":"string"}},"relevance_score":{"type":["number","null"],"format":"double"}}},"MarketReward":{"type":"object","description":"Reward info for market API responses","properties":{"min_size":{"type":["number","null"],"format":"double","default":null},"max_spread":{"type":["number","null"],"format":"double","default":null},"daily_rate":{"type":["number","null"],"format":"double","default":null}}},"MarketSortBy":{"type":"string","enum":["volume","txns","unique_traders","liquidity","holders","end_time","start_time","created_time","relevance"]},"MarketStatus":{"type":"string","enum":["open","closed","all"]},"MarketVolumeChartResponse":{"type":"object","required":["volumes","has_more"],"properties":{"volumes":{"type":"array","items":{"$ref":"#/components/schemas/MarketVolumeDataPoint"}},"has_more":{"type":"boolean"}}},"MarketVolumeDataPoint":{"type":"object","required":["t","v","yv","nv","tc","ytc","ntc"],"properties":{"t":{"type":"integer","format":"int64"},"v":{"type":"number","format":"double"},"yv":{"type":"number","format":"double"},"nv":{"type":"number","format":"double"},"tc":{"type":"integer","format":"int32"},"ytc":{"type":"integer","format":"int32"},"ntc":{"type":"integer","format":"int32"}}},"MetricsTimeframe":{"type":"string","enum":["1m","5m","30m","1h","6h","24h","7d","30d"]},"OrderbookHistoryRow":{"type":"object","required":["ts","position_id","condition_id","bids","asks","hash"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"bids":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"asks":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"hash":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}},"OrderbookLevel":{"type":"object","description":"A single price level in a bids/asks array.","required":["p","s"],"properties":{"p":{"type":"string","description":"Price as a decimal string"},"s":{"type":"string","description":"Size as a decimal string"}}},"OrderbookSnapshotRow":{"type":"object","required":["ts","position_id","condition_id","bids","asks","hash"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"bids":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"asks":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"hash":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}},"OutcomeHolders":{"type":"object","description":"Holder data grouped by outcome for market-level queries","required":["outcome_index","outcome_name","position_id","total_holders","holders"],"properties":{"outcome_index":{"type":"integer","format":"int32","description":"Outcome index (0, 1, etc.)"},"outcome_name":{"type":"string","description":"Outcome name (Yes, No, etc.)"},"position_id":{"type":"string","description":"Position ID for this outcome"},"price":{"type":["number","null"],"format":"double","description":"Current price/probability"},"total_holders":{"type":"integer","format":"int64","description":"Total holders count from holder_stats"},"holders":{"type":"array","items":{"$ref":"#/components/schemas/Holder"},"description":"Top holders for this outcome"}}},"OutcomeIndex":{"type":"string","enum":["0","1"]},"OutcomeTimeframeMetrics":{"type":"object","properties":{"volume":{"type":"number","format":"double","default":0},"buy_volume":{"type":"number","format":"double","default":0},"sell_volume":{"type":"number","format":"double","default":0},"txns":{"type":"integer","format":"int32","default":0},"buys":{"type":"integer","format":"int32","default":0},"sells":{"type":"integer","format":"int32","default":0},"price_open":{"type":["number","null"],"format":"double","default":null},"price_close":{"type":["number","null"],"format":"double","default":null},"price_high":{"type":["number","null"],"format":"double","default":null},"price_low":{"type":["number","null"],"format":"double","default":null},"probability_open":{"type":["number","null"],"format":"double","default":null},"probability_close":{"type":["number","null"],"format":"double","default":null},"probability_high":{"type":["number","null"],"format":"double","default":null},"probability_low":{"type":["number","null"],"format":"double","default":null},"price_change_percent":{"type":["number","null"],"format":"double","default":null}}},"PaginationMeta":{"type":"object","description":"Pagination metadata to include in API responses","required":["has_more"],"properties":{"has_more":{"type":"boolean","description":"Whether there are more results available"},"pagination_key":{"type":["string","null"],"description":"Pagination key for the next page (if has_more is true)"}}},"PnlCandleEntry":{"type":"object","description":"A single PnL candle entry","required":["t","pnl"],"properties":{"t":{"type":"integer","format":"int64","description":"Timestamp in epoch seconds (start of bucket window)"},"pnl":{"type":"number","format":"double","description":"Realized PnL in this bucket (USD)"}}},"PnlCandleResolution":{"type":"string","enum":["1m","1h","1d"]},"PnlCandleTimeframe":{"type":"string","enum":["1d","7d","30d","lifetime"]},"PnlTimeframe":{"type":"string","enum":["1d","7d","30d","lifetime"]},"PolymarketEvent":{"type":"object","description":"A Polymarket event from the Gamma API","properties":{"id":{"type":"string","default":""},"event_slug":{"type":["string","null"],"default":null},"title":{"type":["string","null"],"default":null},"ticker":{"type":["string","null"],"default":null},"description":{"type":["string","null"],"default":null},"resolution_source":{"type":["string","null"],"default":null},"category":{"type":["string","null"],"default":null},"image_url":{"type":["string","null"],"default":null},"market_count":{"type":"integer","format":"int32","default":0},"created_time":{"type":["integer","null"],"format":"int64","default":null},"closed_time":{"type":["integer","null"],"format":"int64","default":null},"start_time":{"type":["integer","null"],"format":"int64","default":null},"end_time":{"type":["integer","null"],"format":"int64","default":null},"neg_risk":{"type":"boolean","default":false},"neg_risk_market_id":{"type":["string","null"],"default":null},"game_status":{"type":["string","null"],"default":null},"show_market_images":{"type":"boolean","default":false},"status":{"type":["string","null"],"description":"Event status: \"open\" or \"closed\"","default":null},"metrics":{"type":"object","default":{},"additionalProperties":{"$ref":"#/components/schemas/SimpleTimeframeMetrics"},"propertyNames":{"type":"string"}},"tags":{"type":"array","items":{"$ref":"#/components/schemas/PolymarketTag"},"default":[]},"markets":{"type":"array","items":{"$ref":"#/components/schemas/EventMarket"},"default":[]},"series":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PolymarketSeries"}],"default":null}}},"PolymarketSeries":{"type":"object","description":"A Polymarket series from the Gamma API\nSeries are parent groupings above events (e.g., \"NBA Season 2024-25\")","properties":{"id":{"type":"string","default":""},"slug":{"type":["string","null"],"default":null},"ticker":{"type":["string","null"],"default":null},"title":{"type":["string","null"],"default":null},"description":{"type":["string","null"],"default":null},"series_type":{"type":["string","null"],"default":null},"recurrence":{"type":["string","null"],"default":null},"layout":{"type":["string","null"],"default":null},"image_url":{"type":["string","null"],"default":null},"icon_url":{"type":["string","null"],"default":null},"active":{"type":"boolean","default":false},"closed":{"type":"boolean","default":false},"archived":{"type":"boolean","default":false},"featured":{"type":"boolean","default":false},"restricted":{"type":"boolean","default":false},"pyth_token_id":{"type":["string","null"],"default":null},"cg_asset_name":{"type":["string","null"],"default":null},"start_date":{"type":["integer","null"],"format":"int64","default":null},"event_count":{"type":"integer","format":"int32","default":0}}},"PolymarketTag":{"type":"object","description":"A Polymarket tag from the Gamma API","properties":{"id":{"type":"string","default":""},"label":{"type":"string","default":""},"slug":{"type":["string","null"],"default":null}}},"PolymarketUserProfile":{"type":"object","description":"Polymarket user profile (public API format)","required":["proxy_wallet","display_username_public","verified_badge","is_creator","is_mod"],"properties":{"proxy_wallet":{"type":"string"},"name":{"type":["string","null"]},"pseudonym":{"type":["string","null"]},"bio":{"type":["string","null"]},"profile_image":{"type":["string","null"]},"x_username":{"type":["string","null"]},"display_username_public":{"type":"boolean"},"verified_badge":{"type":"boolean"},"user_id":{"type":["string","null"]},"is_creator":{"type":"boolean"},"is_mod":{"type":"boolean"},"created_at":{"type":["string","null"]}}},"PositionChartDataPoint":{"type":"object","required":["v","t"],"properties":{"v":{"type":"number","format":"double"},"t":{"type":"integer","format":"int64","minimum":0}}},"PositionChartOutcome":{"type":"object","required":["position_id","name","outcome_index","data"],"properties":{"position_id":{"type":"string"},"name":{"type":"string"},"outcome_index":{"type":"integer","format":"int32"},"data":{"type":"array","items":{"$ref":"#/components/schemas/PositionChartDataPoint"}}}},"PositionHoldersResponse":{"type":"object","description":"Response for position (position_id) holders endpoint","required":["position_id","total_holders","holders"],"properties":{"position_id":{"type":"string","description":"Position ID (ERC1155 token ID)"},"condition_id":{"type":["string","null"],"description":"Condition ID this position belongs to"},"outcome_name":{"type":["string","null"],"description":"Outcome name"},"outcome_index":{"type":["integer","null"],"format":"int32","description":"Outcome index"},"price":{"type":["number","null"],"format":"double","description":"Current price"},"total_holders":{"type":"integer","format":"int64","description":"Total holders count from holder_stats"},"holders":{"type":"array","items":{"$ref":"#/components/schemas/Holder"},"description":"Top holders"}}},"PositionMetricsResponse":{"type":"object","description":"Response type for position metrics query","required":["position_id","condition_id","timeframe","volume_usd","buy_volume_usd","sell_volume_usd","fees","txns","buys","sells","unique_traders","price_open","price_high","price_low","price_close"],"properties":{"position_id":{"type":"string"},"condition_id":{"type":"string"},"timeframe":{"type":"string"},"volume_usd":{"type":"number","format":"double"},"buy_volume_usd":{"type":"number","format":"double"},"sell_volume_usd":{"type":"number","format":"double"},"fees":{"type":"number","format":"double"},"txns":{"type":"integer","format":"int32"},"buys":{"type":"integer","format":"int32"},"sells":{"type":"integer","format":"int32"},"unique_traders":{"type":"integer","format":"int32"},"price_open":{"type":"number","format":"double"},"price_high":{"type":"number","format":"double"},"price_low":{"type":"number","format":"double"},"price_close":{"type":"number","format":"double"}}},"PositionPnlSortBy":{"type":"string","enum":["realized_pnl_usd","buy_usd","sell_usd","redemption_usd","total_buys","total_sells","total_shares_bought","total_shares_sold","avg_entry_price","avg_exit_price","total_fees","first_trade_at","last_trade_at","current_value","realized_pnl_pct","title"]},"PositionVolumeChartResponse":{"type":"object","required":["volumes","has_more"],"properties":{"volumes":{"type":"array","items":{"$ref":"#/components/schemas/PositionVolumeDataPoint"}},"has_more":{"type":"boolean"}}},"PositionVolumeDataPoint":{"type":"object","required":["t","v","bv","sv","tc","btc","stc"],"properties":{"t":{"type":"integer","format":"int64"},"v":{"type":"number","format":"double"},"bv":{"type":"number","format":"double"},"sv":{"type":"number","format":"double"},"tc":{"type":"integer","format":"int32"},"btc":{"type":"integer","format":"int32"},"stc":{"type":"integer","format":"int32"}}},"PredictionCandlestickBar":{"type":"object","required":["t"],"properties":{"l":{"type":["number","null"],"format":"double"},"h":{"type":["number","null"],"format":"double"},"o":{"type":["number","null"],"format":"double"},"c":{"type":["number","null"],"format":"double"},"v":{"type":["number","null"],"format":"double"},"t":{"type":"integer","format":"int64","minimum":0},"tc":{"type":["integer","null"],"format":"int32"},"m":{"type":["number","null"],"format":"double"}}},"PredictionTradeResponse":{"type":"object","description":"Response format for prediction trades","required":["id","hash","block","confirmed_at","trader","taker","usd_amount","shares_amount","price","fee","exchange","trade_type","log_index","order_hash","position_id"],"properties":{"id":{"type":"string"},"hash":{"type":"string"},"block":{"type":"integer","format":"int64","minimum":0},"confirmed_at":{"type":"integer","format":"int64","minimum":0},"trader":{"$ref":"#/components/schemas/TraderInfo"},"taker":{"type":"string"},"side":{"type":["string","null"]},"condition_id":{"type":["string","null"]},"outcome":{"type":["string","null"]},"outcome_index":{"type":["integer","null"],"format":"int32"},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"slug":{"type":["string","null"]},"usd_amount":{"type":"number","format":"double"},"shares_amount":{"type":"number","format":"double"},"price":{"type":"number","format":"double"},"probability":{"type":["number","null"],"format":"double"},"fee":{"type":"number","format":"double"},"exchange":{"type":"string"},"trade_type":{"type":"string"},"log_index":{"type":"integer","format":"int64","minimum":0},"order_hash":{"type":"string"},"position_id":{"type":"string"}}},"PriceJump":{"type":"object","required":["from","to","price_before","price_after","change_pct","direction","volume","trades_count","condition_id"],"properties":{"from":{"type":"integer","format":"int64","minimum":0},"to":{"type":"integer","format":"int64","minimum":0},"price_before":{"type":"number","format":"double"},"price_after":{"type":"number","format":"double"},"change_pct":{"type":"number","format":"double"},"direction":{"type":"string"},"volume":{"type":"number","format":"double"},"trades_count":{"type":"integer","format":"int32"},"condition_id":{"type":"string"}}},"SearchResponse":{"type":"object","properties":{"events":{"type":["array","null"],"items":{"$ref":"#/components/schemas/PolymarketEvent"}},"events_pagination":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PaginationMeta"}]},"markets":{"type":["array","null"],"items":{"$ref":"#/components/schemas/MarketResponse"}},"markets_pagination":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PaginationMeta"}]},"traders":{"type":["array","null"],"items":{"$ref":"#/components/schemas/TraderWithPnl"}},"traders_pagination":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PaginationMeta"}]}}},"SearchSortBy":{"type":"string","description":"Combined sort options valid for both events and markets in search","enum":["volume","txns","unique_traders","relevance","title","creation_date","start_date","end_date","liquidity","holders","end_time","start_time","created_time"]},"SimpleTimeframeMetrics":{"type":"object","properties":{"volume":{"type":"number","format":"double","default":0},"fees":{"type":"number","format":"double","default":0},"txns":{"type":"integer","format":"int32","default":0},"unique_traders":{"type":"integer","format":"int32","default":0}}},"SortDirection":{"type":"string","enum":["asc","desc"]},"SpikeDirection":{"type":"string","description":"Direction filter for spike webhooks.","enum":["up","down","both"]},"SpreadRow":{"type":"object","description":"Lightweight row — derived metrics only, no bids/asks JSONB.","required":["ts","position_id","condition_id"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}},"TokenOutcome":{"type":"object","description":"Token outcome (position)","required":["token_id","outcome"],"properties":{"token_id":{"type":"string"},"outcome":{"type":"string"}}},"TradeSide":{"type":"string","enum":["0","1"]},"TradeType":{"type":"string","enum":["0","1","2","4","6"]},"Trader":{"type":"object","description":"Trader profile info embedded in API responses\n\nCorresponds to SQL function: `pm_build_trader(address, name, pseudonym, profile_image, x_username, verified_badge)`\n\nUsed in:\n- holders endpoints (market/event holders)\n- trades endpoints\n- leaderboard endpoints","required":["address"],"properties":{"address":{"type":"string"},"name":{"type":["string","null"]},"pseudonym":{"type":["string","null"]},"profile_image":{"type":["string","null"]},"x_username":{"type":["string","null"]},"verified_badge":{"type":"boolean"}}},"TraderEventPnlEntry":{"type":"object","description":"Event-level PnL entry","properties":{"event_slug":{"type":["string","null"]},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"markets_traded":{"type":["integer","null"],"format":"int64"},"outcomes_traded":{"type":["integer","null"],"format":"int64"},"total_buys":{"type":["integer","null"],"format":"int64"},"total_sells":{"type":["integer","null"],"format":"int64"},"total_redemptions":{"type":["integer","null"],"format":"int64"},"total_merges":{"type":["integer","null"],"format":"int64"},"total_volume_usd":{"type":["number","null"],"format":"double"},"buy_usd":{"type":["number","null"],"format":"double"},"sell_usd":{"type":["number","null"],"format":"double"},"redemption_usd":{"type":["number","null"],"format":"double"},"merge_usd":{"type":["number","null"],"format":"double"},"realized_pnl_usd":{"type":["number","null"],"format":"double"},"winning_markets":{"type":["integer","null"],"format":"int64"},"losing_markets":{"type":["integer","null"],"format":"int64"},"total_fees":{"type":["number","null"],"format":"double"},"first_trade_at":{"type":["integer","null"],"format":"int64"},"last_trade_at":{"type":["integer","null"],"format":"int64"}}},"TraderInfo":{"type":"object","description":"Trader profile info - backwards compatibility","required":["address"],"properties":{"address":{"type":"string"},"name":{"type":["string","null"]},"pseudonym":{"type":["string","null"]},"profile_image":{"type":["string","null"]},"x_username":{"type":["string","null"]},"verified_badge":{"type":"boolean"}}},"TraderMarketPnlEntry":{"type":"object","description":"Market-level PnL entry","properties":{"condition_id":{"type":["string","null"]},"event_slug":{"type":["string","null"]},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"outcomes_traded":{"type":["integer","null"],"format":"int64"},"total_buys":{"type":["integer","null"],"format":"int64"},"total_sells":{"type":["integer","null"],"format":"int64"},"total_redemptions":{"type":["integer","null"],"format":"int64"},"total_merges":{"type":["integer","null"],"format":"int64"},"buy_usd":{"type":["number","null"],"format":"double"},"sell_usd":{"type":["number","null"],"format":"double"},"redemption_usd":{"type":["number","null"],"format":"double"},"merge_usd":{"type":["number","null"],"format":"double"},"realized_pnl_usd":{"type":["number","null"],"format":"double"},"winning_outcomes":{"type":["integer","null"],"format":"int64"},"total_fees":{"type":["number","null"],"format":"double"},"first_trade_at":{"type":["integer","null"],"format":"int64"},"last_trade_at":{"type":["integer","null"],"format":"int64"}}},"TraderOutcomePnlEntry":{"type":"object","description":"Outcome-level PnL entry (per outcome token / position_id)","properties":{"position_id":{"type":["string","null"]},"condition_id":{"type":["string","null"]},"market_slug":{"type":["string","null"]},"event_slug":{"type":["string","null"]},"title":{"type":["string","null"]},"image_url":{"type":["string","null"]},"outcome":{"type":["string","null"]},"outcome_index":{"type":["integer","null"],"format":"int32"},"won":{"type":["boolean","null"],"description":"TRUE = won, FALSE = lost, NULL = open or sold before resolution"},"total_buys":{"type":["integer","null"],"format":"int64"},"total_sells":{"type":["integer","null"],"format":"int64"},"total_shares_bought":{"type":["number","null"],"format":"double"},"total_shares_sold":{"type":["number","null"],"format":"double"},"total_buy_usd":{"type":["number","null"],"format":"double"},"total_sell_usd":{"type":["number","null"],"format":"double"},"redemption_usd":{"type":["number","null"],"format":"double","description":"Payout on redemption (non-zero only if won)"},"avg_entry_price":{"type":["number","null"],"format":"double","description":"VWAP price paid per share across all buys (0–1)"},"avg_exit_price":{"type":["number","null"],"format":"double","description":"VWAP price received per share across all sells (0–1)"},"realized_pnl_usd":{"type":["number","null"],"format":"double"},"total_fees":{"type":["number","null"],"format":"double"},"first_trade_at":{"type":["integer","null"],"format":"int64"},"last_trade_at":{"type":["integer","null"],"format":"int64"},"current_price":{"type":["number","null"],"format":"double","description":"Last traded price for this outcome (0–1). NULL if market_outcomes has no price yet."},"current_shares_balance":{"type":["number","null"],"format":"double","description":"Current shares held: balance / 1e6."},"current_value":{"type":["number","null"],"format":"double","description":"Estimated current USD value of held shares: (balance / 1e6) * current_price.\nOnly meaningful for open positions (balance > 0)."},"realized_pnl_pct":{"type":["number","null"],"format":"double","description":"Realized PnL as a percentage of total spend: (realized_pnl_usd / total_buy_usd) * 100.\nNULL when total_buy_usd = 0."}}},"TraderPnlSummary":{"type":"object","description":"Trader's global PnL summary (single trader)","properties":{"trader":{"type":["string","null"]},"realized_pnl_usd":{"type":["number","null"],"format":"double"},"events_traded":{"type":["integer","null"],"format":"int64"},"markets_traded":{"type":["integer","null"],"format":"int64"},"total_buys":{"type":["integer","null"],"format":"int64"},"total_sells":{"type":["integer","null"],"format":"int64"},"total_redemptions":{"type":["integer","null"],"format":"int64"},"total_merges":{"type":["integer","null"],"format":"int64"},"total_volume_usd":{"type":["number","null"],"format":"double"},"buy_volume_usd":{"type":["number","null"],"format":"double"},"sell_volume_usd":{"type":["number","null"],"format":"double"},"redemption_volume_usd":{"type":["number","null"],"format":"double"},"merge_volume_usd":{"type":["number","null"],"format":"double"},"markets_won":{"type":["integer","null"],"format":"int64"},"markets_lost":{"type":["integer","null"],"format":"int64"},"market_win_rate_pct":{"type":["number","null"],"format":"double"},"avg_pnl_per_market":{"type":["number","null"],"format":"double"},"avg_pnl_per_trade":{"type":["number","null"],"format":"double"},"avg_hold_time_seconds":{"type":["number","null"],"format":"double"},"total_fees":{"type":["number","null"],"format":"double"},"best_trade_pnl_usd":{"type":["number","null"],"format":"double"},"best_trade_condition_id":{"type":["string","null"]},"first_trade_at":{"type":["integer","null"],"format":"int64"},"last_trade_at":{"type":["integer","null"],"format":"int64"}}},"TraderVolumeChartResponse":{"type":"object","required":["volumes","has_more"],"properties":{"volumes":{"type":"array","items":{"$ref":"#/components/schemas/TraderVolumeDataPoint"}},"has_more":{"type":"boolean"}}},"TraderVolumeDataPoint":{"type":"object","required":["t","v","bv","sv","tc","btc","stc"],"properties":{"t":{"type":"integer","format":"int64"},"v":{"type":"number","format":"double"},"bv":{"type":"number","format":"double"},"sv":{"type":"number","format":"double"},"tc":{"type":"integer","format":"int32"},"btc":{"type":"integer","format":"int32"},"stc":{"type":"integer","format":"int32"}}},"TraderWithPnl":{"allOf":[{"$ref":"#/components/schemas/Trader"},{"type":"object","properties":{"pnl":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/TraderPnlSummary"}]}}}]},"WebhookAssetSymbol":{"type":"string","description":"Crypto asset symbols accepted by `asset_price_tick` and `asset_price_window_update` filters.","enum":["BTC","ETH","SOL","XRP","DOGE","BNB","HYPE"]},"WebhookTimeframe":{"type":"string","description":"Timeframe values accepted by webhook metric, milestone, spike, and asset-price filters.","enum":["1m","5m","15m","30m","1h","4h","6h","1d","24h","7d","30d"]}}}} \ No newline at end of file diff --git a/openapi/webhooks.json b/openapi/webhooks.json index fbd116c..8619e61 100644 --- a/openapi/webhooks.json +++ b/openapi/webhooks.json @@ -1325,20 +1325,6 @@ ], "description": "Condition ID of the best trade" }, - "worst_trade_pnl_usd": { - "type": [ - "number", - "null" - ], - "description": "Worst single-trade PnL in USD" - }, - "worst_trade_condition_id": { - "type": [ - "string", - "null" - ], - "description": "Condition ID of the worst trade" - }, "first_trade_at": { "type": [ "integer", diff --git a/openapi/ws.json b/openapi/ws.json index c54db54..82e4f79 100644 --- a/openapi/ws.json +++ b/openapi/ws.json @@ -121,6 +121,20 @@ } } }, + "polymarket_trader_positions": { + "address": "polymarket_trader_positions", + "title": "Trader Positions", + "summary": "Trader position updates stream", + "description": "Real-time position updates for tracked traders. Streams full position snapshots whenever a position PnL changes in the database.\n\n**Filter (required):** `traders` — EVM wallet addresses. Invalid addresses are returned in `rejected`.\n\n**Events pushed:** `trader_position_update` — includes PnL fields, shares balance, market slug, outcome, and all enriched data.\n\n**Unsubscribe:** Send `action: \"unsubscribe_all\"`.", + "messages": { + "subscribe": { + "$ref": "#/components/messages/TraderPositionsSubscribe" + }, + "traderPositionUpdateEvent": { + "$ref": "#/components/messages/TraderPositionUpdateEvent" + } + } + }, "polymarket_accounts": { "address": "polymarket_accounts", "title": "Accounts", @@ -334,6 +348,30 @@ } ] }, + "subscribePolymarketTraderPositions": { + "action": "send", + "channel": { + "$ref": "#/channels/polymarket_trader_positions" + }, + "summary": "Subscribe to trader position updates stream", + "messages": [ + { + "$ref": "#/channels/polymarket_trader_positions/messages/subscribe" + } + ] + }, + "receivePolymarketTraderPositions": { + "action": "receive", + "channel": { + "$ref": "#/channels/polymarket_trader_positions" + }, + "summary": "Receive trader position updates stream events", + "messages": [ + { + "$ref": "#/channels/polymarket_trader_positions/messages/traderPositionUpdateEvent" + } + ] + }, "subscribePolymarketAccounts": { "action": "send", "channel": { @@ -493,6 +531,18 @@ "$ref": "#/components/schemas/TraderEventPnlEvent" } }, + "TraderPositionsSubscribe": { + "summary": "Subscribe to trader position updates stream", + "payload": { + "$ref": "#/components/schemas/TraderPositionsSubscribeMessage" + } + }, + "TraderPositionUpdateEvent": { + "summary": "TraderPositionUpdateEvent", + "payload": { + "$ref": "#/components/schemas/TraderPositionUpdateEvent" + } + }, "AccountsSubscribe": { "summary": "Subscribe to account balances stream", "payload": { diff --git a/src/generated/polymarket.ts b/src/generated/polymarket.ts index 0e36fd7..89f26bf 100644 --- a/src/generated/polymarket.ts +++ b/src/generated/polymarket.ts @@ -1099,12 +1099,12 @@ export interface components { /** @enum {string} */ EventSortBy: "volume" | "txns" | "unique_traders" | "title" | "creation_date" | "start_date" | "end_date" | "relevance"; /** @enum {string} */ - GlobalPnlSortBy: "pnl_usd" | "buys" | "sells" | "redemptions" | "merges" | "avg_hold_time" | "markets_traded" | "events_traded" | "markets_won" | "volume_usd" | "fees" | "best_trade" | "worst_trade"; + GlobalPnlSortBy: "realized_pnl_usd" | "buys" | "sells" | "redemptions" | "merges" | "avg_hold_time" | "markets_traded" | "events_traded" | "markets_won" | "volume_usd" | "fees" | "best_trade"; /** @description Individual trader entry in the global PnL leaderboard */ GlobalPnlTrader: { trader: components["schemas"]["TraderInfo"]; /** Format: double */ - pnl_usd?: number | null; + realized_pnl_usd?: number | null; /** Format: int64 */ events_traded?: number | null; /** Format: int64 */ @@ -1146,9 +1146,6 @@ export interface components { /** Format: double */ best_trade_pnl_usd?: number | null; best_trade_condition_id?: string | null; - /** Format: double */ - worst_trade_pnl_usd?: number | null; - worst_trade_condition_id?: string | null; /** Format: int64 */ first_trade_at?: number | null; /** Format: int64 */ @@ -2155,9 +2152,6 @@ export interface components { /** Format: double */ best_trade_pnl_usd?: number | null; best_trade_condition_id?: string | null; - /** Format: double */ - worst_trade_pnl_usd?: number | null; - worst_trade_condition_id?: string | null; /** Format: int64 */ first_trade_at?: number | null; /** Format: int64 */ @@ -3703,7 +3697,7 @@ export interface operations { query?: { /** @description Timeframe: 1d, 7d, 30d, lifetime (default: lifetime) */ timeframe?: components["schemas"]["PnlTimeframe"]; - /** @description Sort: pnl_usd, buys, sells, redemptions, merges, avg_hold_time, markets_traded, events_traded, markets_won, volume_usd, fees, best_trade, worst_trade (default: pnl_usd) */ + /** @description Sort: realized_pnl_usd, buys, sells, redemptions, merges, avg_hold_time, markets_traded, events_traded, markets_won, volume_usd, fees, best_trade (default: realized_pnl_usd) */ sort_by?: components["schemas"]["GlobalPnlSortBy"]; /** @description Sort direction: asc, desc (default: desc) */ sort_direction?: components["schemas"]["SortDirection"]; @@ -3914,6 +3908,8 @@ export interface operations { market_slug?: string; /** @description Filter by specific outcome token (position ID) */ position_id?: string; + /** @description Minimum shares balance to include (e.g. 1.0 to filter out dust positions) */ + min_shares?: number; }; header?: never; path: { diff --git a/src/generated/webhooks.ts b/src/generated/webhooks.ts index 860310c..fc67585 100644 --- a/src/generated/webhooks.ts +++ b/src/generated/webhooks.ts @@ -925,10 +925,6 @@ export interface components { best_trade_pnl_usd?: number | null; /** @description Condition ID of the best trade */ best_trade_condition_id?: string | null; - /** @description Worst single-trade PnL in USD */ - worst_trade_pnl_usd?: number | null; - /** @description Condition ID of the worst trade */ - worst_trade_condition_id?: string | null; /** * Format: int64 * @description Timestamp of the first trade (Unix seconds) diff --git a/src/types/index.ts b/src/types/index.ts index 975f952..d82b88f 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -413,6 +413,9 @@ export type { TraderPnlSubscribeFilters, AccountsSubscribeFilters, OrderBookSubscribeFilters, + TraderPositionsSubscribeFilters, + TraderPositionsSubscribeResponse, + TraderPositionUpdateEvent, TradeStreamEvent, AssetPriceTickEvent, AssetPriceWindowUpdateEvent, diff --git a/src/types/ws.ts b/src/types/ws.ts index d8602b4..362d909 100644 --- a/src/types/ws.ts +++ b/src/types/ws.ts @@ -18,6 +18,7 @@ export type WsRoomId = | "polymarket_event_metrics" | "polymarket_position_metrics" | "polymarket_trader_pnl" + | "polymarket_trader_positions" | "polymarket_accounts" | "polymarket_order_book"; @@ -35,6 +36,18 @@ export type AccountsSubscribeFilters = Pick>; export type OrderBookSubscribeFilters = Omit; +export interface TraderPositionsSubscribeFilters { + traders: string[]; +} + +export interface TraderPositionsSubscribeResponse { + traders?: string[]; + rejected?: string[]; + error?: string | null; +} + +export type TraderPositionUpdateEvent = Record; + export type TradeStreamEvent = WsSchemas["TradeStreamEvent"]; export type AssetPriceTickEvent = WsSchemas["AssetPriceTickEvent"]; export type AssetPriceWindowUpdateEvent = WsSchemas["AssetPriceWindowUpdateEvent"]; @@ -78,6 +91,7 @@ export interface WebSocketEventMap { usdce_update: UsdceUpdateEvent; matic_update: MaticUpdateEvent; order_book_update: OrderBookUpdateEvent; + trader_position_update: TraderPositionUpdateEvent; connected: void; disconnected: { code: number; reason: string }; reconnecting: { attempt: number }; @@ -92,6 +106,7 @@ export interface WsSubscriptionMap { polymarket_event_metrics: EventMetricsSubscribeFilters; polymarket_position_metrics: PositionMetricsSubscribeFilters; polymarket_trader_pnl: TraderPnlSubscribeFilters; + polymarket_trader_positions: TraderPositionsSubscribeFilters; polymarket_accounts: AccountsSubscribeFilters; polymarket_order_book: OrderBookSubscribeFilters; } @@ -104,6 +119,7 @@ export interface WsSubscribeResponseMap { polymarket_event_metrics: EventMetricsSubscribeResponse; polymarket_position_metrics: PositionMetricsSubscribeResponse; polymarket_trader_pnl: TraderPnlSubscribeResponse; + polymarket_trader_positions: TraderPositionsSubscribeResponse; polymarket_accounts: AccountsSubscribeResponse; polymarket_order_book: OrderBookSubscribeResponse; } From 5aedff1ef60d319aca203925b2f747b1765e6f37 Mon Sep 17 00:00:00 2001 From: elliotdotsol Date: Sat, 4 Apr 2026 22:27:06 +0700 Subject: [PATCH 07/12] update: types --- openapi/ws.json | 1866 ++++++++++++++++++++++++++++++++----------- package.json | 2 +- src/generated/ws.ts | 588 ++++++++++---- src/types/index.ts | 5 +- src/types/ws.ts | 26 +- 5 files changed, 1854 insertions(+), 633 deletions(-) diff --git a/openapi/ws.json b/openapi/ws.json index 82e4f79..c66c23a 100644 --- a/openapi/ws.json +++ b/openapi/ws.json @@ -3,7 +3,7 @@ "info": { "title": "Polymarket WebSocket API", "version": "1.0.0", - "description": "Real-time WebSocket streaming API for Polymarket prediction-market data.\n\n## Connection\nConnect to `wss://api.struct.to/ws` using a standard WebSocket client.\n\n## Authentication\nAn API key is required. Pass it via **header** or **query parameter**:\n\n**Header (recommended):**\n```\nX-Api-Key: \n```\n\n**Query parameter (browser / frontend):**\n```\nwss://api.struct.to/ws?api_key=\n```\n\nThe query parameter is only used when no `X-Api-Key` header is present.\n\n## Joining a room\nAfter connecting, send:\n```json\n{\"type\":\"join_room\",\"payload\":{\"room_id\":\"polymarket_trades\"}}\n```\n\n## Subscribing\nAfter joining, send a `room_message` with room-specific subscribe payload:\n```json\n{\n\"type\": \"room_message\",\n\"payload\": {\n\"room_id\": \"polymarket_trades\",\n\"message\": {\"action\":\"subscribe\",\"condition_ids\":[\"0xabc…\"]}\n}\n}\n```\n\n## Keepalive\nThe server sends a `ping` text frame every **30 seconds**. Respond with a `pong` text frame to stay connected. Connections that do not respond within **60 seconds** (two missed pings) are closed." + "description": "Real-time WebSocket streaming API for Polymarket prediction-market data.\n\n## Connection\nConnect to `wss://api.struct.to/ws` using a standard WebSocket client.\n\n## Authentication\nAn API key is required. Pass it via **header** or **query parameter**:\n\n**Header (recommended):**\n```\nX-Api-Key: \n```\n\n**Query parameter (browser / frontend):**\n```\nwss://api.struct.to/ws?api_key=\n```\n\nThe query parameter is only used when no `X-Api-Key` header is present.\n\n## Joining a room\nAfter connecting, send:\n```json\n{\"type\":\"join_room\",\"payload\":{\"room_id\":\"polymarket_trades\"}}\n```\n\n## Subscribing\nAfter joining, send a `room_message` with room-specific subscribe payload:\n```json\n{\n\"type\": \"room_message\",\n\"payload\": {\n\"room_id\": \"polymarket_trades\",\n\"message\": {\"action\":\"subscribe\",\"condition_ids\":[\"0xabc…\"]}\n}\n}\n```\n\n## Keepalive\nSend `{\"type\":\"ping\"}` periodically to keep your connection alive. The server responds with `{\"type\":\"pong\"}`. Connections that have not sent a `ping` within **60 seconds** are closed." }, "servers": { "production": { @@ -63,7 +63,7 @@ "address": "polymarket_market_metrics", "title": "Market Metrics", "summary": "Market (condition) metrics stream", - "description": "Real-time volume and transaction-count metrics per market condition, aggregated across multiple timeframes (`1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`).\n\n**Filter (required):** `condition_ids` — 64-char hex condition IDs. Invalid or malformed IDs are returned in `rejected`.\n\n**Unsubscribe:** Send `action: \"unsubscribe_all\"`.", + "description": "Real-time volume and transaction-count metrics per market condition, aggregated across multiple timeframes (`1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`). One event is pushed per timeframe window on each update.\n\n**Filter (required):** `condition_ids` — 64-char hex condition IDs. Invalid or malformed IDs are returned in `rejected`.\n\n**Unsubscribe:** Send `action: \"unsubscribe_all\"`.", "messages": { "subscribe": { "$ref": "#/components/messages/MarketMetricsSubscribe" @@ -77,7 +77,7 @@ "address": "polymarket_event_metrics", "title": "Event Metrics", "summary": "Event metrics stream", - "description": "Real-time volume and transaction-count metrics aggregated at the event (parent market group) level, across multiple timeframes.\n\n**Filter (required):** `event_slugs` — event slugs (lowercase).\n\n**Unsubscribe:** Send `action: \"unsubscribe_all\"`.", + "description": "Real-time volume and transaction-count metrics aggregated at the event (parent market group) level, across multiple timeframes. One event is pushed per timeframe window on each update.\n\n**Filter (required):** `event_slugs` — event slugs (lowercase).\n\n**Unsubscribe:** Send `action: \"unsubscribe_all\"`.", "messages": { "subscribe": { "$ref": "#/components/messages/EventMetricsSubscribe" @@ -91,7 +91,7 @@ "address": "polymarket_position_metrics", "title": "Position Metrics", "summary": "Position (outcome token) metrics stream", - "description": "Real-time volume and transaction-count metrics per outcome-token position, across multiple timeframes.\n\n**Filter (required):** `position_ids` — ERC-1155 token IDs (decimal or hex; normalized to decimal strings internally).\n\n**Unsubscribe:** Send `action: \"unsubscribe_all\"`.", + "description": "Real-time volume, trade-count, and OHLC price/probability metrics per outcome-token position, across multiple timeframes. One event is pushed per timeframe window on each update.\n\n**Filter (required):** `position_ids` — ERC-1155 token IDs (decimal or hex; normalized to decimal strings internally).\n\n**Unsubscribe:** Send `action: \"unsubscribe_all\"`.", "messages": { "subscribe": { "$ref": "#/components/messages/PositionMetricsSubscribe" @@ -168,6 +168,20 @@ "$ref": "#/components/messages/OrderBookUpdateEvent" } } + }, + "polymarket_wallet_tracking": { + "address": "polymarket_wallet_tracking", + "title": "Wallet Tracking", + "summary": "Wallet trade tracking stream", + "description": "Real-time trade alerts for tracked Polymarket wallets. Streams a `wallet_tracking_alert` event whenever a subscribed wallet executes a trade, enriched with market metadata (slug, question, outcome, image).\n\n**Filter (required):** `wallet_addresses` — EVM wallet addresses to track.\n\n**Unsubscribe:** Disconnect or re-subscribe with a new address list.", + "messages": { + "subscribe": { + "$ref": "#/components/messages/WalletTrackingSubscribe" + }, + "walletTrackingAlertEvent": { + "$ref": "#/components/messages/WalletTrackingAlertEvent" + } + } } }, "operations": { @@ -425,6 +439,30 @@ "$ref": "#/channels/polymarket_order_book/messages/orderBookUpdateEvent" } ] + }, + "subscribePolymarketWalletTracking": { + "action": "send", + "channel": { + "$ref": "#/channels/polymarket_wallet_tracking" + }, + "summary": "Subscribe to wallet trade tracking stream", + "messages": [ + { + "$ref": "#/channels/polymarket_wallet_tracking/messages/subscribe" + } + ] + }, + "receivePolymarketWalletTracking": { + "action": "receive", + "channel": { + "$ref": "#/channels/polymarket_wallet_tracking" + }, + "summary": "Receive wallet trade tracking stream events", + "messages": [ + { + "$ref": "#/channels/polymarket_wallet_tracking/messages/walletTrackingAlertEvent" + } + ] } }, "components": { @@ -466,7 +504,7 @@ } }, "AssetWindowUpdateEvent": { - "summary": "Server-pushed event from the polymarket_asset_window_updates room", + "summary": "Server-pushed event from the polymarket_asset_window_updates room. Same payload as AssetPriceWindowUpdateEvent", "payload": { "$ref": "#/components/schemas/AssetWindowUpdateEvent" } @@ -478,7 +516,7 @@ } }, "MarketMetricsEvent": { - "summary": "updated metrics for a condition", + "summary": "metrics update for one timeframe of a condition", "payload": { "$ref": "#/components/schemas/MarketMetricsEvent" } @@ -490,7 +528,7 @@ } }, "EventMetricsEvent": { - "summary": "updated aggregated metrics for an event", + "summary": "aggregated metrics update for one timeframe of an event", "payload": { "$ref": "#/components/schemas/EventMetricsEvent" } @@ -502,7 +540,7 @@ } }, "PositionMetricsEvent": { - "summary": "updated metrics for an outcome token", + "summary": "metrics update for one timeframe of an outcome token", "payload": { "$ref": "#/components/schemas/PositionMetricsEvent" } @@ -538,7 +576,7 @@ } }, "TraderPositionUpdateEvent": { - "summary": "TraderPositionUpdateEvent", + "summary": "full position snapshot for a tracked trader", "payload": { "$ref": "#/components/schemas/TraderPositionUpdateEvent" } @@ -578,9 +616,131 @@ "payload": { "$ref": "#/components/schemas/OrderBookUpdateEvent" } + }, + "WalletTrackingSubscribe": { + "summary": "Subscribe to wallet trade tracking stream", + "payload": { + "$ref": "#/components/schemas/WalletTrackingSubscribeMessage" + } + }, + "WalletTrackingAlertEvent": { + "summary": "a trade executed by a tracked wallet", + "payload": { + "$ref": "#/components/schemas/WalletTrackingAlertEvent" + } } }, "schemas": { + "WalletTrackingAlertEvent": { + "type": "object", + "description": "Server-pushed event: a trade executed by a tracked wallet. Envelope type: \"wallet_tracking_alert\".", + "required": [ + "is_buy", + "trader", + "position_id", + "usd_amount", + "shares_amount", + "price", + "confirmed_at" + ], + "properties": { + "is_buy": { + "type": "boolean", + "description": "True = buy, false = sell" + }, + "trader": { + "type": "string", + "description": "Trader EVM wallet address (lowercase)" + }, + "condition_id": { + "type": [ + "string", + "null" + ], + "description": "64-char hex condition ID" + }, + "position_id": { + "type": "string", + "description": "ERC-1155 outcome token ID (decimal string)" + }, + "usd_amount": { + "type": "string", + "description": "USD value of the trade (decimal string, 6dp)" + }, + "shares_amount": { + "type": "string", + "description": "Number of shares traded (decimal string, 6dp)" + }, + "price": { + "type": "number", + "minimum": 0.0, + "maximum": 1.0, + "description": "Trade price (0–1)" + }, + "probability": { + "type": [ + "number", + "null" + ], + "description": "Implied probability (0–1)" + }, + "metadata": { + "oneOf": [ + { + "$ref": "#/components/schemas/PredictionMarketMetadata" + }, + { + "type": "null" + } + ], + "description": "Market metadata — null when enrichment is unavailable" + }, + "confirmed_at": { + "type": "integer", + "format": "int64", + "description": "Unix seconds" + } + } + }, + "PredictionMarketMetadata": { + "type": "object", + "description": "Market metadata enrichment attached to wallet tracking alerts", + "properties": { + "slug": { + "type": [ + "string", + "null" + ], + "description": "Market slug" + }, + "question": { + "type": [ + "string", + "null" + ], + "description": "Market question text" + }, + "outcome": { + "type": [ + "string", + "null" + ], + "description": "Outcome name (e.g. \"Yes\")" + }, + "outcome_index": { + "type": [ + "integer", + "null" + ] + }, + "image_url": { + "type": [ + "string", + "null" + ] + } + } + }, "OrderBookUpdateEvent": { "type": "object", "description": "Server-pushed event: full CLOB orderbook snapshot for an outcome token. Envelope type: \"order_book_update\". Delivered whenever the book changes for a subscribed condition or position.", @@ -691,65 +851,6 @@ "minItems": 2, "maxItems": 2 }, - "OrderBookSubscribeResponse": { - "type": "object", - "description": "Server acknowledgement for an order book subscription", - "properties": { - "condition_ids": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Accepted condition IDs" - }, - "position_ids": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Accepted position IDs" - }, - "rejected": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Filter values that were rejected (invalid format or limit exceeded)" - } - } - }, - "OrderBookSubscribeMessage": { - "type": "object", - "description": "Subscribe to the order book stream. At least one filter is required. Maximum 500 combined condition_ids + position_ids per client.", - "required": [ - "action" - ], - "properties": { - "action": { - "type": "string", - "enum": [ - "subscribe", - "unsubscribe_all" - ] - }, - "condition_ids": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Condition IDs (markets). All positions within each market are delivered.", - "maxItems": 500 - }, - "position_ids": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Token / asset IDs (individual outcome positions, hex strings).", - "maxItems": 500 - } - } - }, "MaticUpdateEvent": { "type": "object", "description": "Server-pushed event: MATIC native balance change for a wallet. Envelope type: \"matic_update\". Only delivered when `include_matic: true`.", @@ -761,11 +862,15 @@ "properties": { "address": { "type": "string", - "description": "Wallet address" + "description": "Wallet address (0x-prefixed hex)" + }, + "token_address": { + "type": "string", + "description": "Native token address — omitted when not available" }, "balance": { - "type": "number", - "description": "Current MATIC balance — omitted when not available" + "type": "string", + "description": "Current MATIC balance (decimal string) — omitted when not available" }, "block_number": { "type": "integer", @@ -1156,314 +1261,1201 @@ } } }, - "TradeStreamEvent": { + "TraderPositionsSubscribeMessage": { "type": "object", - "description": "Server-pushed event: a matched trade on a subscribed market/position/event/slug. Envelope type: \"trade_stream_update\".", + "description": "Subscribe to the trader positions stream. traders is required and must be non-empty.", "required": [ - "trader", - "taker", - "position_id", - "trade_id", - "hash", - "block", - "confirmed_at", - "amount_usd", - "shares_amount", - "fee", - "side", - "price" + "action", + "traders" ], "properties": { - "trader": { - "type": "string", - "description": "Limit-order maker wallet" - }, - "taker": { - "type": "string", - "description": "Order taker wallet" - }, - "position_id": { + "action": { "type": "string", - "description": "ERC-1155 outcome token ID" - }, - "condition_id": { - "type": [ - "string", - "null" + "enum": [ + "subscribe", + "unsubscribe_all" ] }, - "outcome": { - "type": [ - "string", - "null" - ], - "description": "Outcome name (e.g. \"Yes\")" + "traders": { + "type": "array", + "items": { + "type": "string" + }, + "description": "EVM wallet addresses", + "minItems": 1 + } + } + }, + "TraderPositionsSubscribeResponse": { + "type": "object", + "description": "Server acknowledgement for a trader positions subscription", + "properties": { + "traders": { + "type": "array", + "items": { + "type": "string" + } }, - "outcome_index": { - "type": [ - "integer", - "null" - ], - "description": "0 = Yes, 1 = No" + "rejected": { + "type": "array", + "items": { + "type": "string" + } }, - "question": { + "error": { "type": [ "string", "null" ] - }, - "market_slug": { - "type": [ - "string", - "null" + } + } + }, + "AccountsSubscribeMessage": { + "type": "object", + "description": "Subscribe to the accounts stream. `wallets` is required. Share balance updates (`accounts_update`) are always delivered. Set `include_usdce` or `include_matic` to also receive those balance streams.", + "required": [ + "action", + "wallets" + ], + "properties": { + "action": { + "type": "string", + "enum": [ + "subscribe", + "unsubscribe_all" ] }, - "event_slug": { + "wallets": { + "type": "array", + "items": { + "type": "string" + }, + "description": "EVM wallet addresses", + "minItems": 1 + }, + "include_usdce": { + "type": "boolean", + "default": false, + "description": "Also stream USDCe collateral balance updates for subscribed wallets" + }, + "include_matic": { + "type": "boolean", + "default": false, + "description": "Also stream MATIC gas balance updates for subscribed wallets" + } + } + }, + "AccountsSubscribeResponse": { + "type": "object", + "description": "Server acknowledgement for an accounts subscription", + "properties": { + "wallets": { + "type": "array", + "items": { + "type": "string" + } + }, + "rejected": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Addresses rejected (invalid format)" + }, + "include_usdce": { + "type": "boolean" + }, + "include_matic": { + "type": "boolean" + }, + "error": { + "type": [ + "string", + "null" + ] + } + } + }, + "OrderBookSubscribeMessage": { + "type": "object", + "description": "Subscribe to the order book stream. At least one filter is required. Maximum 500 combined condition_ids + position_ids per client. No `type` field is needed — the server routes by room_id.", + "required": [ + "action" + ], + "properties": { + "action": { + "type": "string", + "enum": [ + "subscribe", + "unsubscribe_all" + ] + }, + "condition_ids": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Condition IDs (markets). All positions within each market are delivered.", + "maxItems": 500 + }, + "position_ids": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Token / asset IDs (individual outcome positions, hex strings).", + "maxItems": 500 + } + } + }, + "OrderBookSubscribeResponse": { + "type": "object", + "description": "Server acknowledgement for an order book subscription. Envelope type: \"order_book_stream_subscribe_response\".", + "properties": { + "condition_ids": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Accepted condition IDs" + }, + "position_ids": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Accepted position IDs" + }, + "rejected": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Filter values that were rejected (invalid format or limit exceeded)" + } + } + }, + "WalletTrackingSubscribeMessage": { + "type": "object", + "description": "Subscribe to wallet trade alerts. wallet_addresses is required.", + "required": [ + "action", + "wallet_addresses" + ], + "properties": { + "action": { + "type": "string", + "enum": [ + "subscribe" + ] + }, + "wallet_addresses": { + "type": "array", + "items": { + "type": "string" + }, + "description": "EVM wallet addresses to track", + "minItems": 1 + } + } + }, + "TradeStreamEvent": { + "type": "object", + "description": "Server-pushed event: a matched trade on a subscribed market/position/event/slug. Envelope type: \"trade_stream_update\".", + "required": [ + "id", + "trader", + "taker", + "position_id", + "hash", + "block", + "confirmed_at", + "usd_amount", + "shares_amount", + "fee", + "price" + ], + "properties": { + "id": { + "type": "string", + "description": "Trade ID" + }, + "hash": { + "type": "string", + "description": "Transaction hash (hex)" + }, + "chain_id": { + "type": "integer", + "format": "uint64" + }, + "block": { + "type": "integer", + "format": "uint64" + }, + "confirmed_at": { + "type": "integer", + "format": "uint64", + "description": "Unix seconds" + }, + "log_index": { + "type": "integer", + "format": "uint64" + }, + "block_index": { + "type": "integer", + "format": "uint64" + }, + "order_hash": { + "type": "string", + "description": "Order hash (hex)" + }, + "trader": { + "type": "string", + "description": "Limit-order maker wallet address" + }, + "taker": { + "type": "string", + "description": "Order taker wallet address" + }, + "side": { + "type": [ + "string", + "null" + ], + "description": "\"Buy\" or \"Sell\"" + }, + "condition_id": { + "type": [ + "string", + "null" + ], + "description": "64-char hex condition ID" + }, + "position_id": { + "type": "string", + "description": "ERC-1155 outcome token ID (decimal string)" + }, + "outcome": { + "type": [ + "string", + "null" + ], + "description": "Outcome name (e.g. \"Yes\")" + }, + "outcome_index": { + "type": [ + "integer", + "null" + ], + "description": "0 = Yes, 1 = No" + }, + "question": { + "type": [ + "string", + "null" + ] + }, + "slug": { + "type": [ + "string", + "null" + ], + "description": "Market slug" + }, + "event_slug": { + "type": [ + "string", + "null" + ] + }, + "usd_amount": { + "type": "string", + "description": "USD value of the trade (decimal string)" + }, + "shares_amount": { + "type": "string", + "description": "Number of shares traded (decimal string)" + }, + "price": { + "type": "number", + "minimum": 0.0, + "maximum": 1.0, + "description": "Trade price (0–1)" + }, + "probability": { + "type": [ + "number", + "null" + ], + "description": "Implied probability (0–1)" + }, + "fee": { + "type": "string", + "description": "Protocol fee paid (decimal string)" + }, + "exchange": { + "type": "string", + "description": "Exchange identifier" + }, + "trade_type": { + "type": "string", + "description": "\"OrderFilled\", \"Redemption\", \"Merge\", \"Split\", \"Cancelled\", \"PositionsConverted\", \"OrdersMatched\"" + }, + "winning_outcome_index": { + "type": [ + "integer", + "null" + ], + "description": "Resolved winning outcome index" + }, + "is_known_surebet": { + "type": "boolean" + }, + "is_coordinated": { + "type": "boolean" + }, + "is_surebet_trade": { + "type": "boolean" + }, + "surebet_price_sum": { + "type": [ + "number", + "null" + ] + }, + "is_bot": { + "type": "boolean" + }, + "bot_reason": { + "type": [ + "string", + "null" + ] + } + } + }, + "AssetPriceTickEvent": { + "type": "object", + "description": "Server-pushed event: a crypto-asset price tick. Envelope type: \"asset_price_tick\".", + "required": [ + "event_type", + "symbol", + "price", + "timestamp_ms", + "published_at" + ], + "properties": { + "event_type": { + "type": "string", + "description": "Always \"asset_price_tick\"" + }, + "symbol": { + "type": "string", + "description": "Uppercase asset symbol (e.g. \"BTC\")" + }, + "price": { + "type": "number", + "description": "Current price in USD" + }, + "timestamp_ms": { + "type": "integer", + "format": "int64", + "description": "Event timestamp in Unix milliseconds" + }, + "published_at": { + "type": "integer", + "format": "int64", + "description": "Publish timestamp in Unix milliseconds" + } + } + }, + "AssetPriceWindowUpdateEvent": { + "type": "object", + "description": "Server-pushed event: candle open or close for a crypto asset. Envelope type: \"asset_price_window_update\". Delivered from both `polymarket_asset_prices` and `polymarket_asset_window_updates` rooms.", + "required": [ + "event_type", + "symbol", + "variant", + "start_time", + "end_time", + "open_price", + "close_price", + "update_type", + "published_at" + ], + "properties": { + "event_type": { + "type": "string", + "description": "Always \"asset_price_window_update\"" + }, + "symbol": { + "type": "string", + "description": "Uppercase asset symbol (e.g. \"BTC\")" + }, + "variant": { + "type": "string", + "description": "Candle size / timeframe (e.g. \"5m\", \"1h\", \"1d\")" + }, + "start_time": { + "type": "integer", + "format": "int64", + "description": "Candle start in Unix milliseconds" + }, + "end_time": { + "type": "integer", + "format": "int64", + "description": "Candle end in Unix milliseconds" + }, + "open_price": { + "type": "number", + "description": "Candle open price in USD" + }, + "close_price": { + "type": "number", + "description": "Candle close price in USD" + }, + "update_type": { + "type": "string", + "description": "\"open\" = candle starting, \"close\" = candle finalised" + }, + "published_at": { + "type": "integer", + "format": "int64", + "description": "Publish timestamp in Unix milliseconds" + } + } + }, + "AssetWindowUpdateEvent": { + "allOf": [ + { + "$ref": "#/components/schemas/AssetPriceWindowUpdateEvent" + } + ], + "description": "Server-pushed event from the polymarket_asset_window_updates room. Same payload as AssetPriceWindowUpdateEvent. Envelope type: \"asset_price_window_update\"." + }, + "MarketMetricsEvent": { + "type": "object", + "description": "Server-pushed event: metrics update for one timeframe of a condition. Envelope type: \"market_metrics_update\". One event is emitted per timeframe window on each update.", + "required": [ + "condition_id", + "timeframe", + "usd_volume", + "fees", + "txns", + "unique_traders", + "historical_confirmed_at", + "latest_confirmed_at", + "latest_block" + ], + "properties": { + "condition_id": { + "type": "string", + "description": "64-char hex condition ID" + }, + "timeframe": { + "type": "string", + "enum": [ + "1m", + "5m", + "30m", + "1h", + "6h", + "24h", + "7d", + "30d" + ] + }, + "timestamp": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Optional event timestamp (Unix seconds)" + }, + "usd_volume": { + "type": "string", + "description": "USD volume in this timeframe window (decimal string)" + }, + "fees": { + "type": "number", + "description": "Total fees in this window" + }, + "txns": { + "type": "integer", + "format": "int64", + "description": "Number of transactions" + }, + "unique_traders": { + "type": "integer", + "format": "int64" + }, + "historical_confirmed_at": { + "type": "integer", + "format": "int64", + "description": "Earliest trade timestamp in window (Unix seconds)" + }, + "latest_confirmed_at": { + "type": "integer", + "format": "int64", + "description": "Latest trade timestamp in window (Unix seconds)" + }, + "latest_block": { + "type": "integer", + "format": "int64" + } + } + }, + "EventMetricsEvent": { + "type": "object", + "description": "Server-pushed event: aggregated metrics update for one timeframe of an event. Envelope type: \"event_metrics_update\". One event is emitted per timeframe window on each update.", + "required": [ + "event_slug", + "timeframe", + "usd_volume", + "fees", + "txns", + "unique_traders", + "historical_confirmed_at", + "latest_confirmed_at", + "latest_block" + ], + "properties": { + "event_slug": { + "type": "string" + }, + "timeframe": { + "type": "string", + "enum": [ + "1m", + "5m", + "30m", + "1h", + "6h", + "24h", + "7d", + "30d" + ] + }, + "timestamp": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Optional event timestamp (Unix seconds)" + }, + "usd_volume": { + "type": "string", + "description": "USD volume in this timeframe window (decimal string)" + }, + "fees": { + "type": "number" + }, + "txns": { + "type": "integer", + "format": "int64" + }, + "unique_traders": { + "type": "integer", + "format": "int64" + }, + "historical_confirmed_at": { + "type": "integer", + "format": "int64" + }, + "latest_confirmed_at": { + "type": "integer", + "format": "int64" + }, + "latest_block": { + "type": "integer", + "format": "int64" + } + } + }, + "PositionMetricsEvent": { + "type": "object", + "description": "Server-pushed event: metrics update for one timeframe of an outcome token. Envelope type: \"position_metrics_update\". One event is emitted per timeframe window on each update.", + "required": [ + "condition_id", + "position_id", + "timeframe", + "usd_volume", + "usd_buy_volume", + "usd_sell_volume", + "fees", + "txns", + "buys", + "sells", + "unique_traders", + "price_open", + "price_close", + "price_high", + "price_low", + "probability_open", + "probability_close", + "probability_high", + "probability_low", + "historical_confirmed_at", + "latest_confirmed_at", + "latest_block" + ], + "properties": { + "condition_id": { + "type": "string", + "description": "64-char hex condition ID" + }, + "position_id": { + "type": "string", + "description": "ERC-1155 token ID (decimal string)" + }, + "outcome": { + "type": [ + "string", + "null" + ], + "description": "Outcome name (e.g. \"Yes\")" + }, + "outcome_index": { + "type": [ + "integer", + "null" + ] + }, + "timeframe": { + "type": "string", + "enum": [ + "1m", + "5m", + "30m", + "1h", + "6h", + "24h", + "7d", + "30d" + ] + }, + "timestamp": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Optional event timestamp (Unix seconds)" + }, + "usd_volume": { + "type": "string", + "description": "Total USD volume (decimal string)" + }, + "usd_buy_volume": { + "type": "string", + "description": "USD buy volume (decimal string)" + }, + "usd_sell_volume": { + "type": "string", + "description": "USD sell volume (decimal string)" + }, + "fees": { + "type": "number" + }, + "txns": { + "type": "integer", + "format": "int64" + }, + "buys": { + "type": "integer", + "format": "int64" + }, + "sells": { + "type": "integer", + "format": "int64" + }, + "unique_traders": { + "type": "integer", + "format": "int64" + }, + "price_open": { + "type": "number", + "description": "OHLC open price (0–1)" + }, + "price_close": { + "type": "number", + "description": "OHLC close price (0–1)" + }, + "price_high": { + "type": "number", + "description": "OHLC high price (0–1)" + }, + "price_low": { + "type": "number", + "description": "OHLC low price (0–1)" + }, + "probability_open": { + "type": "number", + "description": "Implied probability at open (0–1)" + }, + "probability_close": { + "type": "number", + "description": "Implied probability at close (0–1)" + }, + "probability_high": { + "type": "number", + "description": "Highest implied probability in window (0–1)" + }, + "probability_low": { + "type": "number", + "description": "Lowest implied probability in window (0–1)" + }, + "historical_confirmed_at": { + "type": "integer", + "format": "int64" + }, + "latest_confirmed_at": { + "type": "integer", + "format": "int64" + }, + "latest_block": { + "type": "integer", + "format": "int64" + } + } + }, + "TraderGlobalPnlEvent": { + "type": "object", + "description": "Server-pushed event: global (portfolio-level) PnL update for a trader. Envelope type: \"trader_global_pnl_update\".", + "required": [ + "trader", + "realized_pnl_usd", + "total_volume_usd", + "buy_volume_usd", + "sell_volume_usd", + "redemption_volume_usd", + "merge_volume_usd", + "market_win_rate_pct", + "avg_pnl_per_market", + "avg_pnl_per_trade", + "avg_hold_time_seconds", + "total_fees", + "best_trade_pnl_usd", + "worst_trade_pnl_usd" + ], + "properties": { + "trader": { + "type": "string", + "description": "Trader EVM wallet address" + }, + "realized_pnl_usd": { + "type": "string", + "description": "Total realized PnL in USD (decimal string)" + }, + "events_traded": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "markets_traded": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "total_buys": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "total_sells": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "total_redemptions": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "total_merges": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "total_volume_usd": { + "type": "string", + "description": "Total USD volume (decimal string)" + }, + "buy_volume_usd": { + "type": "string" + }, + "sell_volume_usd": { + "type": "string" + }, + "redemption_volume_usd": { + "type": "string" + }, + "merge_volume_usd": { + "type": "string" + }, + "markets_won": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "markets_lost": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "market_win_rate_pct": { + "type": "string", + "description": "Win rate percentage (decimal string)" + }, + "avg_pnl_per_market": { + "type": "string" + }, + "avg_pnl_per_trade": { + "type": "string" + }, + "avg_hold_time_seconds": { + "type": "string" + }, + "total_fees": { + "type": "string" + }, + "best_trade_pnl_usd": { + "type": "string" + }, + "best_trade_condition_id": { + "type": [ + "string", + "null" + ] + }, + "worst_trade_pnl_usd": { + "type": "string" + }, + "worst_trade_condition_id": { + "type": [ + "string", + "null" + ] + }, + "first_trade_at": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Unix seconds" + }, + "last_trade_at": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Unix seconds" + }, + "timestamp": { "type": [ - "string", + "integer", "null" - ] + ], + "format": "int64" }, - "trade_id": { + "timeframe": { + "type": [ + "string", + "null" + ], + "description": "\"1d\", \"7d\", \"30d\", or \"lifetime\"" + } + } + }, + "TraderMarketPnlEvent": { + "type": "object", + "description": "Server-pushed event: per-market PnL update for a trader. Envelope type: \"trader_market_pnl_update\".", + "required": [ + "trader", + "condition_id", + "buy_usd", + "sell_usd", + "redemption_usd", + "merge_usd", + "realized_pnl_usd", + "total_fees" + ], + "properties": { + "trader": { "type": "string" }, - "hash": { + "condition_id": { "type": "string", - "description": "Transaction hash" + "description": "64-char hex condition ID" }, - "block": { - "type": "integer", + "event_slug": { + "type": [ + "string", + "null" + ] + }, + "outcomes_traded": { + "type": [ + "integer", + "null" + ], "format": "int64" }, - "confirmed_at": { - "type": "integer", - "format": "int64", - "description": "Unix seconds" + "total_buys": { + "type": [ + "integer", + "null" + ], + "format": "int64" }, - "amount_usd": { - "type": "number" + "total_sells": { + "type": [ + "integer", + "null" + ], + "format": "int64" }, - "shares_amount": { - "type": "number" + "total_redemptions": { + "type": [ + "integer", + "null" + ], + "format": "int64" }, - "fee": { - "type": "number" + "total_merges": { + "type": [ + "integer", + "null" + ], + "format": "int64" }, - "side": { + "buy_usd": { "type": "string", - "enum": [ - "Buy", - "Sell" - ] + "description": "Total buy volume in USD (decimal string)" }, - "price": { - "type": "number", - "minimum": 0.0, - "maximum": 1.0 - } - } - }, - "AssetPriceTickEvent": { - "type": "object", - "description": "Server-pushed event: a crypto-asset price tick. Envelope type: \"asset_price_tick\".", - "required": [ - "symbol", - "price", - "timestamp" - ], - "properties": { - "symbol": { + "sell_usd": { + "type": "string" + }, + "redemption_usd": { + "type": "string" + }, + "merge_usd": { + "type": "string" + }, + "realized_pnl_usd": { "type": "string", - "description": "Uppercase asset symbol (e.g. \"BTC\")" + "description": "Realized PnL in USD (decimal string)" }, - "price": { - "type": "number", - "description": "Current price in USD" + "winning_outcomes": { + "type": [ + "integer", + "null" + ], + "format": "int64" }, - "timestamp": { - "type": "integer", + "total_fees": { + "type": "string" + }, + "first_trade_at": { + "type": [ + "integer", + "null" + ], "format": "int64", - "description": "Unix milliseconds" + "description": "Unix seconds" }, - "change_24h": { + "last_trade_at": { "type": [ - "number", + "integer", "null" ], - "description": "24-hour price change %" + "format": "int64", + "description": "Unix seconds" }, - "volume_24h": { + "timestamp": { "type": [ - "number", + "integer", "null" ], - "description": "24-hour trading volume USD" + "format": "int64" }, - "market_cap": { + "timeframe": { "type": [ - "number", + "string", "null" - ] + ], + "description": "\"1d\", \"7d\", \"30d\", or \"lifetime\"" } } }, - "AssetPriceWindowUpdateEvent": { + "TraderEventPnlEvent": { "type": "object", - "description": "Server-pushed event: candle open or close for a crypto asset. Envelope type: \"asset_price_window_update\".", + "description": "Server-pushed event: per-event PnL update for a trader. Envelope type: \"trader_event_pnl_update\".", "required": [ - "symbol", - "timeframe", - "update_type", - "open", - "close", - "high", - "low", - "timestamp" + "trader", + "event_slug", + "buy_usd", + "sell_usd", + "redemption_usd", + "merge_usd", + "total_volume_usd", + "realized_pnl_usd", + "total_fees" ], "properties": { - "symbol": { - "type": "string", - "description": "Uppercase asset symbol" + "trader": { + "type": "string" }, - "timeframe": { - "type": "string", - "enum": [ - "5m", - "15m", - "1h", - "4h", - "1d", - "24h" - ] + "event_slug": { + "type": "string" }, - "update_type": { - "type": "string", - "enum": [ - "open", - "close" + "markets_traded": { + "type": [ + "integer", + "null" ], - "description": "\"open\" = candle starting, \"close\" = candle finalised" + "format": "int64" }, - "open": { - "type": "number" + "outcomes_traded": { + "type": [ + "integer", + "null" + ], + "format": "int64" }, - "close": { - "type": "number" + "total_buys": { + "type": [ + "integer", + "null" + ], + "format": "int64" }, - "high": { - "type": "number" + "total_sells": { + "type": [ + "integer", + "null" + ], + "format": "int64" }, - "low": { - "type": "number" + "total_redemptions": { + "type": [ + "integer", + "null" + ], + "format": "int64" }, - "volume": { + "total_merges": { "type": [ - "number", + "integer", "null" - ] + ], + "format": "int64" }, - "timestamp": { - "type": "integer", - "format": "int64", - "description": "Candle start time in Unix milliseconds" - } - } - }, - "AssetWindowUpdateEvent": { - "allOf": [ - { - "$ref": "#/components/schemas/AssetPriceWindowUpdateEvent" - } - ], - "description": "Server-pushed event from the polymarket_asset_window_updates room. Envelope type: \"asset_window_update\"." - }, - "MetricsTimeframe": { - "type": "object", - "description": "Volume and trade-count metrics for one timeframe window", - "required": [ - "timeframe", - "volume_usd", - "trade_count" - ], - "properties": { - "timeframe": { + "total_volume_usd": { "type": "string", - "enum": [ - "1m", - "5m", - "30m", - "1h", - "6h", - "24h", - "7d", - "30d" - ] + "description": "Total USD volume (decimal string)" }, - "volume_usd": { - "type": "number", - "description": "USD volume in this window" + "buy_usd": { + "type": "string" }, - "trade_count": { - "type": "integer", - "description": "Number of trades in this window" - } - } - }, - "MarketMetricsEvent": { - "type": "object", - "description": "Server-pushed event: updated metrics for a condition. Envelope type: \"market_metrics_update\".", - "required": [ - "condition_id", - "timeframes" - ], - "properties": { - "condition_id": { + "sell_usd": { + "type": "string" + }, + "redemption_usd": { + "type": "string" + }, + "merge_usd": { + "type": "string" + }, + "realized_pnl_usd": { "type": "string", - "description": "0x-prefixed 64-char hex condition ID" + "description": "Realized PnL in USD (decimal string)" + }, + "winning_markets": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "losing_markets": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "total_fees": { + "type": "string" + }, + "first_trade_at": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Unix seconds" + }, + "last_trade_at": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Unix seconds" }, - "market_slug": { + "timestamp": { "type": [ - "string", + "integer", "null" - ] + ], + "format": "int64" }, - "timeframes": { - "type": "array", - "items": { - "$ref": "#/components/schemas/MetricsTimeframe" - } + "timeframe": { + "type": [ + "string", + "null" + ], + "description": "\"1d\", \"7d\", \"30d\", or \"lifetime\"" } } }, - "EventMetricsEvent": { + "TraderPositionUpdateEvent": { "type": "object", - "description": "Server-pushed event: updated aggregated metrics for an event. Envelope type: \"event_metrics_update\".", + "description": "Server-pushed event: full position snapshot for a tracked trader. Envelope type: \"trader_position_update\". Pushed whenever a position's PnL changes in the database.", "required": [ - "event_slug", - "timeframes" + "trader" ], "properties": { - "event_slug": { - "type": "string" + "trader": { + "type": "string", + "description": "Trader EVM wallet address" }, - "timeframes": { - "type": "array", - "items": { - "$ref": "#/components/schemas/MetricsTimeframe" - } - } - } - }, - "PositionMetricsEvent": { - "type": "object", - "description": "Server-pushed event: updated metrics for an outcome token. Envelope type: \"position_metrics_update\".", - "required": [ - "position_id", - "timeframes" - ], - "properties": { "position_id": { - "type": "string", + "type": [ + "string", + "null" + ], "description": "ERC-1155 token ID (decimal string)" }, "condition_id": { @@ -1472,236 +2464,150 @@ "null" ] }, - "outcome": { + "market_slug": { "type": [ "string", "null" ] }, - "timeframes": { - "type": "array", - "items": { - "$ref": "#/components/schemas/MetricsTimeframe" - } - } - } - }, - "PnlTimeframes": { - "type": "object", - "description": "PnL figures broken down by timeframe", - "properties": { - "1d": { + "event_slug": { "type": [ - "number", + "string", + "null" + ] + }, + "title": { + "type": [ + "string", "null" ], - "description": "1-day PnL in USD" + "description": "Market title / question" }, - "7d": { + "image_url": { "type": [ - "number", + "string", "null" ] }, - "30d": { + "outcome": { "type": [ - "number", + "string", + "null" + ], + "description": "Outcome name (e.g. \"Yes\")" + }, + "outcome_index": { + "type": [ + "integer", "null" ] }, - "all": { + "won": { "type": [ - "number", + "boolean", "null" ], - "description": "All-time PnL in USD" - } - } - }, - "TraderGlobalPnlEvent": { - "type": "object", - "description": "Server-pushed event: global (portfolio-level) PnL update for a trader. Envelope type: \"trader_global_pnl_update\".", - "required": [ - "trader", - "realized_pnl", - "unrealized_pnl", - "timeframe" - ], - "properties": { - "trader": { - "type": "string", - "description": "Trader EVM address" + "description": "True if this outcome resolved as winner" }, - "realized_pnl": { - "type": "number", - "description": "Realized PnL in USD" + "total_buys": { + "type": [ + "integer", + "null" + ], + "format": "int64" }, - "unrealized_pnl": { - "type": "number", - "description": "Unrealized PnL in USD" + "total_sells": { + "type": [ + "integer", + "null" + ], + "format": "int64" }, - "total_pnl": { + "total_shares_bought": { "type": [ "number", "null" ] }, - "timeframe": { - "type": "string", - "description": "Window that triggered the update" - }, - "updated_at": { - "type": "integer", - "format": "int64", - "description": "Unix seconds" - } - } - }, - "TraderMarketPnlEvent": { - "type": "object", - "description": "Server-pushed event: per-market PnL update for a trader. Envelope type: \"trader_market_pnl_update\".", - "required": [ - "trader", - "condition_id", - "realized_pnl", - "unrealized_pnl", - "timeframe" - ], - "properties": { - "trader": { - "type": "string" - }, - "condition_id": { - "type": "string" - }, - "market_slug": { + "total_shares_sold": { "type": [ - "string", + "number", "null" ] }, - "realized_pnl": { - "type": "number" - }, - "unrealized_pnl": { - "type": "number" - }, - "total_pnl": { + "total_buy_usd": { "type": [ "number", "null" ] }, - "timeframe": { - "type": "string" - }, - "updated_at": { - "type": "integer", - "format": "int64" - } - } - }, - "TraderEventPnlEvent": { - "type": "object", - "description": "Server-pushed event: per-event PnL update for a trader. Envelope type: \"trader_event_pnl_update\".", - "required": [ - "trader", - "event_slug", - "realized_pnl", - "unrealized_pnl", - "timeframe" - ], - "properties": { - "trader": { - "type": "string" + "total_sell_usd": { + "type": [ + "number", + "null" + ] }, - "event_slug": { - "type": "string" + "redemption_usd": { + "type": [ + "number", + "null" + ] }, - "realized_pnl": { - "type": "number" + "avg_entry_price": { + "type": [ + "number", + "null" + ], + "description": "Average entry price (0–1)" }, - "unrealized_pnl": { - "type": "number" + "avg_exit_price": { + "type": [ + "number", + "null" + ], + "description": "Average exit price (0–1)" }, - "total_pnl": { + "realized_pnl_usd": { "type": [ "number", "null" ] }, - "timeframe": { - "type": "string" - }, - "updated_at": { - "type": "integer", - "format": "int64" - } - } - }, - "AccountsSubscribeMessage": { - "type": "object", - "description": "Subscribe to the accounts stream. `wallets` is required. Share balance updates (`accounts_update`) are always delivered. Set `include_usdce` or `include_matic` to also receive those balance streams.", - "required": [ - "action", - "wallets" - ], - "properties": { - "action": { - "type": "string", - "enum": [ - "subscribe", - "unsubscribe_all" + "total_fees": { + "type": [ + "number", + "null" ] }, - "wallets": { - "type": "array", - "items": { - "type": "string" - }, - "description": "EVM wallet addresses", - "minItems": 1 - }, - "include_usdce": { - "type": "boolean", - "default": false, - "description": "Also stream USDCe collateral balance updates for subscribed wallets" - }, - "include_matic": { - "type": "boolean", - "default": false, - "description": "Also stream MATIC gas balance updates for subscribed wallets" - } - } - }, - "AccountsSubscribeResponse": { - "type": "object", - "description": "Server acknowledgement for an accounts subscription", - "properties": { - "wallets": { - "type": "array", - "items": { - "type": "string" - } - }, - "rejected": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Addresses rejected (invalid format)" + "first_trade_at": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Unix seconds" }, - "include_usdce": { - "type": "boolean" + "last_trade_at": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Unix seconds" }, - "include_matic": { - "type": "boolean" + "current_shares_balance": { + "type": [ + "number", + "null" + ], + "description": "Current ERC-1155 token balance" }, - "error": { + "realized_pnl_pct": { "type": [ - "string", + "number", "null" - ] + ], + "description": "Realized PnL as a percentage of cost basis" } } }, @@ -1726,7 +2632,7 @@ }, "balance": { "type": "string", - "description": "Current token balance (U256 as decimal string)" + "description": "Current token balance (decimal string)" }, "block_number": { "type": "integer", @@ -1758,15 +2664,15 @@ "properties": { "address": { "type": "string", - "description": "Wallet address" + "description": "Wallet address (0x-prefixed hex)" }, "token_address": { "type": "string", "description": "USDCe contract address — omitted when not available" }, "balance": { - "type": "number", - "description": "Current USDCe balance — omitted when not available" + "type": "string", + "description": "Current USDCe balance (decimal string) — omitted when not available" }, "block_number": { "type": "integer", diff --git a/package.json b/package.json index fb30c97..a345230 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "generate:polymarket": "openapi-typescript openapi/polymarket.json -o src/generated/polymarket.ts", "fetch-spec:webhooks": "curl -s -o openapi/webhooks.json https://api.struct.to/webhookopenapi.json", "generate:webhooks": "openapi-typescript openapi/webhooks.json -o src/generated/webhooks.ts", - "fetch-spec:ws": "curl -s -o openapi/ws.json https://api.struct.to/asyncapi.json", + "fetch-spec:ws": "curl -s -o openapi/ws.json https://staging-api.struct.to/asyncapi.json", "generate:ws": "bun run scripts/generate-ws-types.ts" }, "devDependencies": { diff --git a/src/generated/ws.ts b/src/generated/ws.ts index 0b01c37..3d61ebb 100644 --- a/src/generated/ws.ts +++ b/src/generated/ws.ts @@ -2,6 +2,43 @@ export type paths = Record; export type webhooks = Record; export interface components { schemas: { + /** @description Server-pushed event: a trade executed by a tracked wallet. Envelope type: "wallet_tracking_alert". */ + WalletTrackingAlertEvent: { + /** @description True = buy, false = sell */ + is_buy: boolean; + /** @description Trader EVM wallet address (lowercase) */ + trader: string; + /** @description 64-char hex condition ID */ + condition_id?: string | null; + /** @description ERC-1155 outcome token ID (decimal string) */ + position_id: string; + /** @description USD value of the trade (decimal string, 6dp) */ + usd_amount: string; + /** @description Number of shares traded (decimal string, 6dp) */ + shares_amount: string; + /** @description Trade price (0–1) */ + price: number; + /** @description Implied probability (0–1) */ + probability?: number | null; + /** @description Market metadata — null when enrichment is unavailable */ + metadata?: components["schemas"]["PredictionMarketMetadata"] | null; + /** + * Format: int64 + * @description Unix seconds + */ + confirmed_at: number; + }; + /** @description Market metadata enrichment attached to wallet tracking alerts */ + PredictionMarketMetadata: { + /** @description Market slug */ + slug?: string | null; + /** @description Market question text */ + question?: string | null; + /** @description Outcome name (e.g. "Yes") */ + outcome?: string | null; + outcome_index?: number | null; + image_url?: string | null; + }; /** @description Server-pushed event: full CLOB orderbook snapshot for an outcome token. Envelope type: "order_book_update". Delivered whenever the book changes for a subscribed condition or position. */ OrderBookUpdateEvent: { /** @description Hex token ID (position / outcome token) */ @@ -38,30 +75,14 @@ export interface components { }; /** @description A single price level: [price_string, size_string] */ OrderBookLevel: string[]; - /** @description Server acknowledgement for an order book subscription */ - OrderBookSubscribeResponse: { - /** @description Accepted condition IDs */ - condition_ids?: string[]; - /** @description Accepted position IDs */ - position_ids?: string[]; - /** @description Filter values that were rejected (invalid format or limit exceeded) */ - rejected?: string[]; - }; - /** @description Subscribe to the order book stream. At least one filter is required. Maximum 500 combined condition_ids + position_ids per client. */ - OrderBookSubscribeMessage: { - /** @enum {string} */ - action: "subscribe" | "unsubscribe_all"; - /** @description Condition IDs (markets). All positions within each market are delivered. */ - condition_ids?: string[]; - /** @description Token / asset IDs (individual outcome positions, hex strings). */ - position_ids?: string[]; - }; /** @description Server-pushed event: MATIC native balance change for a wallet. Envelope type: "matic_update". Only delivered when `include_matic: true`. */ MaticUpdateEvent: { - /** @description Wallet address */ + /** @description Wallet address (0x-prefixed hex) */ address: string; - /** @description Current MATIC balance — omitted when not available */ - balance?: number; + /** @description Native token address — omitted when not available */ + token_address?: string; + /** @description Current MATIC balance (decimal string) — omitted when not available */ + balance?: string; /** Format: uint64 */ block_number: number; /** @@ -174,183 +195,480 @@ export interface components { rejected?: string[]; error?: string | null; }; + /** @description Subscribe to the trader positions stream. traders is required and must be non-empty. */ + TraderPositionsSubscribeMessage: { + /** @enum {string} */ + action: "subscribe" | "unsubscribe_all"; + /** @description EVM wallet addresses */ + traders: string[]; + }; + /** @description Server acknowledgement for a trader positions subscription */ + TraderPositionsSubscribeResponse: { + traders?: string[]; + rejected?: string[]; + error?: string | null; + }; + /** @description Subscribe to the accounts stream. `wallets` is required. Share balance updates (`accounts_update`) are always delivered. Set `include_usdce` or `include_matic` to also receive those balance streams. */ + AccountsSubscribeMessage: { + /** @enum {string} */ + action: "subscribe" | "unsubscribe_all"; + /** @description EVM wallet addresses */ + wallets: string[]; + /** + * @description Also stream USDCe collateral balance updates for subscribed wallets + * @default false + */ + include_usdce: boolean; + /** + * @description Also stream MATIC gas balance updates for subscribed wallets + * @default false + */ + include_matic: boolean; + }; + /** @description Server acknowledgement for an accounts subscription */ + AccountsSubscribeResponse: { + wallets?: string[]; + /** @description Addresses rejected (invalid format) */ + rejected?: string[]; + include_usdce?: boolean; + include_matic?: boolean; + error?: string | null; + }; + /** @description Subscribe to the order book stream. At least one filter is required. Maximum 500 combined condition_ids + position_ids per client. No `type` field is needed — the server routes by room_id. */ + OrderBookSubscribeMessage: { + /** @enum {string} */ + action: "subscribe" | "unsubscribe_all"; + /** @description Condition IDs (markets). All positions within each market are delivered. */ + condition_ids?: string[]; + /** @description Token / asset IDs (individual outcome positions, hex strings). */ + position_ids?: string[]; + }; + /** @description Server acknowledgement for an order book subscription. Envelope type: "order_book_stream_subscribe_response". */ + OrderBookSubscribeResponse: { + /** @description Accepted condition IDs */ + condition_ids?: string[]; + /** @description Accepted position IDs */ + position_ids?: string[]; + /** @description Filter values that were rejected (invalid format or limit exceeded) */ + rejected?: string[]; + }; + /** @description Subscribe to wallet trade alerts. wallet_addresses is required. */ + WalletTrackingSubscribeMessage: { + /** @enum {string} */ + action: "subscribe"; + /** @description EVM wallet addresses to track */ + wallet_addresses: string[]; + }; /** @description Server-pushed event: a matched trade on a subscribed market/position/event/slug. Envelope type: "trade_stream_update". */ TradeStreamEvent: { - /** @description Limit-order maker wallet */ + /** @description Trade ID */ + id: string; + /** @description Transaction hash (hex) */ + hash: string; + /** Format: uint64 */ + chain_id?: number; + /** Format: uint64 */ + block: number; + /** + * Format: uint64 + * @description Unix seconds + */ + confirmed_at: number; + /** Format: uint64 */ + log_index?: number; + /** Format: uint64 */ + block_index?: number; + /** @description Order hash (hex) */ + order_hash?: string; + /** @description Limit-order maker wallet address */ trader: string; - /** @description Order taker wallet */ + /** @description Order taker wallet address */ taker: string; - /** @description ERC-1155 outcome token ID */ - position_id: string; + /** @description "Buy" or "Sell" */ + side?: string | null; + /** @description 64-char hex condition ID */ condition_id?: string | null; + /** @description ERC-1155 outcome token ID (decimal string) */ + position_id: string; /** @description Outcome name (e.g. "Yes") */ outcome?: string | null; /** @description 0 = Yes, 1 = No */ outcome_index?: number | null; question?: string | null; - market_slug?: string | null; + /** @description Market slug */ + slug?: string | null; event_slug?: string | null; - trade_id: string; - /** @description Transaction hash */ - hash: string; - /** Format: int64 */ - block: number; - /** - * Format: int64 - * @description Unix seconds - */ - confirmed_at: number; - amount_usd: number; - shares_amount: number; - fee: number; - /** @enum {string} */ - side: "Buy" | "Sell"; + /** @description USD value of the trade (decimal string) */ + usd_amount: string; + /** @description Number of shares traded (decimal string) */ + shares_amount: string; + /** @description Trade price (0–1) */ price: number; + /** @description Implied probability (0–1) */ + probability?: number | null; + /** @description Protocol fee paid (decimal string) */ + fee: string; + /** @description Exchange identifier */ + exchange?: string; + /** @description "OrderFilled", "Redemption", "Merge", "Split", "Cancelled", "PositionsConverted", "OrdersMatched" */ + trade_type?: string; + /** @description Resolved winning outcome index */ + winning_outcome_index?: number | null; + is_known_surebet?: boolean; + is_coordinated?: boolean; + is_surebet_trade?: boolean; + surebet_price_sum?: number | null; + is_bot?: boolean; + bot_reason?: string | null; }; /** @description Server-pushed event: a crypto-asset price tick. Envelope type: "asset_price_tick". */ AssetPriceTickEvent: { + /** @description Always "asset_price_tick" */ + event_type: string; /** @description Uppercase asset symbol (e.g. "BTC") */ symbol: string; /** @description Current price in USD */ price: number; /** * Format: int64 - * @description Unix milliseconds + * @description Event timestamp in Unix milliseconds */ - timestamp: number; - /** @description 24-hour price change % */ - change_24h?: number | null; - /** @description 24-hour trading volume USD */ - volume_24h?: number | null; - market_cap?: number | null; + timestamp_ms: number; + /** + * Format: int64 + * @description Publish timestamp in Unix milliseconds + */ + published_at: number; }; - /** @description Server-pushed event: candle open or close for a crypto asset. Envelope type: "asset_price_window_update". */ + /** @description Server-pushed event: candle open or close for a crypto asset. Envelope type: "asset_price_window_update". Delivered from both `polymarket_asset_prices` and `polymarket_asset_window_updates` rooms. */ AssetPriceWindowUpdateEvent: { - /** @description Uppercase asset symbol */ + /** @description Always "asset_price_window_update" */ + event_type: string; + /** @description Uppercase asset symbol (e.g. "BTC") */ symbol: string; - /** @enum {string} */ - timeframe: "5m" | "15m" | "1h" | "4h" | "1d" | "24h"; + /** @description Candle size / timeframe (e.g. "5m", "1h", "1d") */ + variant: string; /** - * @description "open" = candle starting, "close" = candle finalised - * @enum {string} + * Format: int64 + * @description Candle start in Unix milliseconds */ - update_type: "open" | "close"; - open: number; - close: number; - high: number; - low: number; - volume?: number | null; + start_time: number; /** * Format: int64 - * @description Candle start time in Unix milliseconds + * @description Candle end in Unix milliseconds */ - timestamp: number; + end_time: number; + /** @description Candle open price in USD */ + open_price: number; + /** @description Candle close price in USD */ + close_price: number; + /** @description "open" = candle starting, "close" = candle finalised */ + update_type: string; + /** + * Format: int64 + * @description Publish timestamp in Unix milliseconds + */ + published_at: number; }; - /** @description Server-pushed event from the polymarket_asset_window_updates room. Envelope type: "asset_window_update". */ + /** @description Server-pushed event from the polymarket_asset_window_updates room. Same payload as AssetPriceWindowUpdateEvent. Envelope type: "asset_price_window_update". */ AssetWindowUpdateEvent: components["schemas"]["AssetPriceWindowUpdateEvent"]; - /** @description Volume and trade-count metrics for one timeframe window */ - MetricsTimeframe: { - /** @enum {string} */ - timeframe: "1m" | "5m" | "30m" | "1h" | "6h" | "24h" | "7d" | "30d"; - /** @description USD volume in this window */ - volume_usd: number; - /** @description Number of trades in this window */ - trade_count: number; - }; - /** @description Server-pushed event: updated metrics for a condition. Envelope type: "market_metrics_update". */ + /** @description Server-pushed event: metrics update for one timeframe of a condition. Envelope type: "market_metrics_update". One event is emitted per timeframe window on each update. */ MarketMetricsEvent: { - /** @description 0x-prefixed 64-char hex condition ID */ + /** @description 64-char hex condition ID */ condition_id: string; - market_slug?: string | null; - timeframes: components["schemas"]["MetricsTimeframe"][]; + /** @enum {string} */ + timeframe: "1m" | "5m" | "30m" | "1h" | "6h" | "24h" | "7d" | "30d"; + /** + * Format: int64 + * @description Optional event timestamp (Unix seconds) + */ + timestamp?: number | null; + /** @description USD volume in this timeframe window (decimal string) */ + usd_volume: string; + /** @description Total fees in this window */ + fees: number; + /** + * Format: int64 + * @description Number of transactions + */ + txns: number; + /** Format: int64 */ + unique_traders: number; + /** + * Format: int64 + * @description Earliest trade timestamp in window (Unix seconds) + */ + historical_confirmed_at: number; + /** + * Format: int64 + * @description Latest trade timestamp in window (Unix seconds) + */ + latest_confirmed_at: number; + /** Format: int64 */ + latest_block: number; }; - /** @description Server-pushed event: updated aggregated metrics for an event. Envelope type: "event_metrics_update". */ + /** @description Server-pushed event: aggregated metrics update for one timeframe of an event. Envelope type: "event_metrics_update". One event is emitted per timeframe window on each update. */ EventMetricsEvent: { event_slug: string; - timeframes: components["schemas"]["MetricsTimeframe"][]; + /** @enum {string} */ + timeframe: "1m" | "5m" | "30m" | "1h" | "6h" | "24h" | "7d" | "30d"; + /** + * Format: int64 + * @description Optional event timestamp (Unix seconds) + */ + timestamp?: number | null; + /** @description USD volume in this timeframe window (decimal string) */ + usd_volume: string; + fees: number; + /** Format: int64 */ + txns: number; + /** Format: int64 */ + unique_traders: number; + /** Format: int64 */ + historical_confirmed_at: number; + /** Format: int64 */ + latest_confirmed_at: number; + /** Format: int64 */ + latest_block: number; }; - /** @description Server-pushed event: updated metrics for an outcome token. Envelope type: "position_metrics_update". */ + /** @description Server-pushed event: metrics update for one timeframe of an outcome token. Envelope type: "position_metrics_update". One event is emitted per timeframe window on each update. */ PositionMetricsEvent: { + /** @description 64-char hex condition ID */ + condition_id: string; /** @description ERC-1155 token ID (decimal string) */ position_id: string; - condition_id?: string | null; + /** @description Outcome name (e.g. "Yes") */ outcome?: string | null; - timeframes: components["schemas"]["MetricsTimeframe"][]; - }; - /** @description PnL figures broken down by timeframe */ - PnlTimeframes: { - /** @description 1-day PnL in USD */ - "1d"?: number | null; - "7d"?: number | null; - "30d"?: number | null; - /** @description All-time PnL in USD */ - all?: number | null; + outcome_index?: number | null; + /** @enum {string} */ + timeframe: "1m" | "5m" | "30m" | "1h" | "6h" | "24h" | "7d" | "30d"; + /** + * Format: int64 + * @description Optional event timestamp (Unix seconds) + */ + timestamp?: number | null; + /** @description Total USD volume (decimal string) */ + usd_volume: string; + /** @description USD buy volume (decimal string) */ + usd_buy_volume: string; + /** @description USD sell volume (decimal string) */ + usd_sell_volume: string; + fees: number; + /** Format: int64 */ + txns: number; + /** Format: int64 */ + buys: number; + /** Format: int64 */ + sells: number; + /** Format: int64 */ + unique_traders: number; + /** @description OHLC open price (0–1) */ + price_open: number; + /** @description OHLC close price (0–1) */ + price_close: number; + /** @description OHLC high price (0–1) */ + price_high: number; + /** @description OHLC low price (0–1) */ + price_low: number; + /** @description Implied probability at open (0–1) */ + probability_open: number; + /** @description Implied probability at close (0–1) */ + probability_close: number; + /** @description Highest implied probability in window (0–1) */ + probability_high: number; + /** @description Lowest implied probability in window (0–1) */ + probability_low: number; + /** Format: int64 */ + historical_confirmed_at: number; + /** Format: int64 */ + latest_confirmed_at: number; + /** Format: int64 */ + latest_block: number; }; /** @description Server-pushed event: global (portfolio-level) PnL update for a trader. Envelope type: "trader_global_pnl_update". */ TraderGlobalPnlEvent: { - /** @description Trader EVM address */ + /** @description Trader EVM wallet address */ trader: string; - /** @description Realized PnL in USD */ - realized_pnl: number; - /** @description Unrealized PnL in USD */ - unrealized_pnl: number; - total_pnl?: number | null; - /** @description Window that triggered the update */ - timeframe: string; + /** @description Total realized PnL in USD (decimal string) */ + realized_pnl_usd: string; + /** Format: int64 */ + events_traded?: number | null; + /** Format: int64 */ + markets_traded?: number | null; + /** Format: int64 */ + total_buys?: number | null; + /** Format: int64 */ + total_sells?: number | null; + /** Format: int64 */ + total_redemptions?: number | null; + /** Format: int64 */ + total_merges?: number | null; + /** @description Total USD volume (decimal string) */ + total_volume_usd: string; + buy_volume_usd: string; + sell_volume_usd: string; + redemption_volume_usd: string; + merge_volume_usd: string; + /** Format: int64 */ + markets_won?: number | null; + /** Format: int64 */ + markets_lost?: number | null; + /** @description Win rate percentage (decimal string) */ + market_win_rate_pct: string; + avg_pnl_per_market: string; + avg_pnl_per_trade: string; + avg_hold_time_seconds: string; + total_fees: string; + best_trade_pnl_usd: string; + best_trade_condition_id?: string | null; + worst_trade_pnl_usd: string; + worst_trade_condition_id?: string | null; + /** + * Format: int64 + * @description Unix seconds + */ + first_trade_at?: number | null; /** * Format: int64 * @description Unix seconds */ - updated_at?: number; + last_trade_at?: number | null; + /** Format: int64 */ + timestamp?: number | null; + /** @description "1d", "7d", "30d", or "lifetime" */ + timeframe?: string | null; }; /** @description Server-pushed event: per-market PnL update for a trader. Envelope type: "trader_market_pnl_update". */ TraderMarketPnlEvent: { trader: string; + /** @description 64-char hex condition ID */ condition_id: string; - market_slug?: string | null; - realized_pnl: number; - unrealized_pnl: number; - total_pnl?: number | null; - timeframe: string; + event_slug?: string | null; + /** Format: int64 */ + outcomes_traded?: number | null; + /** Format: int64 */ + total_buys?: number | null; + /** Format: int64 */ + total_sells?: number | null; + /** Format: int64 */ + total_redemptions?: number | null; /** Format: int64 */ - updated_at?: number; + total_merges?: number | null; + /** @description Total buy volume in USD (decimal string) */ + buy_usd: string; + sell_usd: string; + redemption_usd: string; + merge_usd: string; + /** @description Realized PnL in USD (decimal string) */ + realized_pnl_usd: string; + /** Format: int64 */ + winning_outcomes?: number | null; + total_fees: string; + /** + * Format: int64 + * @description Unix seconds + */ + first_trade_at?: number | null; + /** + * Format: int64 + * @description Unix seconds + */ + last_trade_at?: number | null; + /** Format: int64 */ + timestamp?: number | null; + /** @description "1d", "7d", "30d", or "lifetime" */ + timeframe?: string | null; }; /** @description Server-pushed event: per-event PnL update for a trader. Envelope type: "trader_event_pnl_update". */ TraderEventPnlEvent: { trader: string; event_slug: string; - realized_pnl: number; - unrealized_pnl: number; - total_pnl?: number | null; - timeframe: string; /** Format: int64 */ - updated_at?: number; - }; - /** @description Subscribe to the accounts stream. `wallets` is required. Share balance updates (`accounts_update`) are always delivered. Set `include_usdce` or `include_matic` to also receive those balance streams. */ - AccountsSubscribeMessage: { - /** @enum {string} */ - action: "subscribe" | "unsubscribe_all"; - /** @description EVM wallet addresses */ - wallets: string[]; + markets_traded?: number | null; + /** Format: int64 */ + outcomes_traded?: number | null; + /** Format: int64 */ + total_buys?: number | null; + /** Format: int64 */ + total_sells?: number | null; + /** Format: int64 */ + total_redemptions?: number | null; + /** Format: int64 */ + total_merges?: number | null; + /** @description Total USD volume (decimal string) */ + total_volume_usd: string; + buy_usd: string; + sell_usd: string; + redemption_usd: string; + merge_usd: string; + /** @description Realized PnL in USD (decimal string) */ + realized_pnl_usd: string; + /** Format: int64 */ + winning_markets?: number | null; + /** Format: int64 */ + losing_markets?: number | null; + total_fees: string; /** - * @description Also stream USDCe collateral balance updates for subscribed wallets - * @default false + * Format: int64 + * @description Unix seconds */ - include_usdce: boolean; + first_trade_at?: number | null; /** - * @description Also stream MATIC gas balance updates for subscribed wallets - * @default false + * Format: int64 + * @description Unix seconds */ - include_matic: boolean; + last_trade_at?: number | null; + /** Format: int64 */ + timestamp?: number | null; + /** @description "1d", "7d", "30d", or "lifetime" */ + timeframe?: string | null; }; - /** @description Server acknowledgement for an accounts subscription */ - AccountsSubscribeResponse: { - wallets?: string[]; - /** @description Addresses rejected (invalid format) */ - rejected?: string[]; - include_usdce?: boolean; - include_matic?: boolean; - error?: string | null; + /** @description Server-pushed event: full position snapshot for a tracked trader. Envelope type: "trader_position_update". Pushed whenever a position's PnL changes in the database. */ + TraderPositionUpdateEvent: { + /** @description Trader EVM wallet address */ + trader: string; + /** @description ERC-1155 token ID (decimal string) */ + position_id?: string | null; + condition_id?: string | null; + market_slug?: string | null; + event_slug?: string | null; + /** @description Market title / question */ + title?: string | null; + image_url?: string | null; + /** @description Outcome name (e.g. "Yes") */ + outcome?: string | null; + outcome_index?: number | null; + /** @description True if this outcome resolved as winner */ + won?: boolean | null; + /** Format: int64 */ + total_buys?: number | null; + /** Format: int64 */ + total_sells?: number | null; + total_shares_bought?: number | null; + total_shares_sold?: number | null; + total_buy_usd?: number | null; + total_sell_usd?: number | null; + redemption_usd?: number | null; + /** @description Average entry price (0–1) */ + avg_entry_price?: number | null; + /** @description Average exit price (0–1) */ + avg_exit_price?: number | null; + realized_pnl_usd?: number | null; + total_fees?: number | null; + /** + * Format: int64 + * @description Unix seconds + */ + first_trade_at?: number | null; + /** + * Format: int64 + * @description Unix seconds + */ + last_trade_at?: number | null; + /** @description Current ERC-1155 token balance */ + current_shares_balance?: number | null; + /** @description Realized PnL as a percentage of cost basis */ + realized_pnl_pct?: number | null; }; /** @description Server-pushed event: ERC-1155 outcome token balance change for a wallet. Envelope type: "accounts_update". */ AccountsUpdateEvent: { @@ -358,7 +676,7 @@ export interface components { wallet: string; /** @description ERC-1155 outcome token ID (decimal string) */ position_id: string; - /** @description Current token balance (U256 as decimal string) */ + /** @description Current token balance (decimal string) */ balance: string; /** Format: int64 */ block_number: number; @@ -374,12 +692,12 @@ export interface components { }; /** @description Server-pushed event: USDCe collateral balance change for a wallet. Envelope type: "usdce_update". Only delivered when `include_usdce: true`. */ UsdceUpdateEvent: { - /** @description Wallet address */ + /** @description Wallet address (0x-prefixed hex) */ address: string; /** @description USDCe contract address — omitted when not available */ token_address?: string; - /** @description Current USDCe balance — omitted when not available */ - balance?: number; + /** @description Current USDCe balance (decimal string) — omitted when not available */ + balance?: string; /** Format: uint64 */ block_number: number; /** diff --git a/src/types/index.ts b/src/types/index.ts index d82b88f..47a56c6 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -416,15 +416,16 @@ export type { TraderPositionsSubscribeFilters, TraderPositionsSubscribeResponse, TraderPositionUpdateEvent, + WalletTrackingSubscribeFilters, + WalletTrackingAlertEvent, + WsPredictionMarketMetadata, TradeStreamEvent, AssetPriceTickEvent, AssetPriceWindowUpdateEvent, AssetWindowUpdateEvent, - WsMetricsTimeframe, MarketMetricsEvent, EventMetricsEvent, PositionMetricsEvent, - WsPnlTimeframes, TraderGlobalPnlEvent, TraderMarketPnlEvent, TraderEventPnlEvent, diff --git a/src/types/ws.ts b/src/types/ws.ts index 362d909..344c1a2 100644 --- a/src/types/ws.ts +++ b/src/types/ws.ts @@ -20,7 +20,8 @@ export type WsRoomId = | "polymarket_trader_pnl" | "polymarket_trader_positions" | "polymarket_accounts" - | "polymarket_order_book"; + | "polymarket_order_book" + | "polymarket_wallet_tracking"; export type WsFiltersOptionalRoom = "polymarket_asset_prices"; export type WsFiltersRequiredRoom = Exclude; @@ -35,28 +36,16 @@ export type TraderPnlSubscribeFilters = Omit & Partial>; export type OrderBookSubscribeFilters = Omit; - -export interface TraderPositionsSubscribeFilters { - traders: string[]; -} - -export interface TraderPositionsSubscribeResponse { - traders?: string[]; - rejected?: string[]; - error?: string | null; -} - -export type TraderPositionUpdateEvent = Record; +export type TraderPositionsSubscribeFilters = Omit; +export type WalletTrackingSubscribeFilters = Omit; export type TradeStreamEvent = WsSchemas["TradeStreamEvent"]; export type AssetPriceTickEvent = WsSchemas["AssetPriceTickEvent"]; export type AssetPriceWindowUpdateEvent = WsSchemas["AssetPriceWindowUpdateEvent"]; export type AssetWindowUpdateEvent = WsSchemas["AssetWindowUpdateEvent"]; -export type WsMetricsTimeframe = WsSchemas["MetricsTimeframe"]; export type MarketMetricsEvent = WsSchemas["MarketMetricsEvent"]; export type EventMetricsEvent = WsSchemas["EventMetricsEvent"]; export type PositionMetricsEvent = WsSchemas["PositionMetricsEvent"]; -export type WsPnlTimeframes = WsSchemas["PnlTimeframes"]; export type TraderGlobalPnlEvent = WsSchemas["TraderGlobalPnlEvent"]; export type TraderMarketPnlEvent = WsSchemas["TraderMarketPnlEvent"]; export type TraderEventPnlEvent = WsSchemas["TraderEventPnlEvent"]; @@ -65,6 +54,10 @@ export type UsdceUpdateEvent = WsSchemas["UsdceUpdateEvent"]; export type MaticUpdateEvent = WsSchemas["MaticUpdateEvent"]; export type WsOrderBookLevel = WsSchemas["OrderBookLevel"]; export type OrderBookUpdateEvent = WsSchemas["OrderBookUpdateEvent"]; +export type TraderPositionUpdateEvent = WsSchemas["TraderPositionUpdateEvent"]; +export type TraderPositionsSubscribeResponse = WsSchemas["TraderPositionsSubscribeResponse"]; +export type WalletTrackingAlertEvent = WsSchemas["WalletTrackingAlertEvent"]; +export type WsPredictionMarketMetadata = WsSchemas["PredictionMarketMetadata"]; export type TradesStreamSubscribeResponse = WsSchemas["TradesStreamSubscribeResponse"]; export type AssetPricesSubscribeResponse = WsSchemas["AssetPricesSubscribeResponse"]; @@ -92,6 +85,7 @@ export interface WebSocketEventMap { matic_update: MaticUpdateEvent; order_book_update: OrderBookUpdateEvent; trader_position_update: TraderPositionUpdateEvent; + wallet_tracking_alert: WalletTrackingAlertEvent; connected: void; disconnected: { code: number; reason: string }; reconnecting: { attempt: number }; @@ -109,6 +103,7 @@ export interface WsSubscriptionMap { polymarket_trader_positions: TraderPositionsSubscribeFilters; polymarket_accounts: AccountsSubscribeFilters; polymarket_order_book: OrderBookSubscribeFilters; + polymarket_wallet_tracking: WalletTrackingSubscribeFilters; } export interface WsSubscribeResponseMap { @@ -122,4 +117,5 @@ export interface WsSubscribeResponseMap { polymarket_trader_positions: TraderPositionsSubscribeResponse; polymarket_accounts: AccountsSubscribeResponse; polymarket_order_book: OrderBookSubscribeResponse; + polymarket_wallet_tracking: Record; } From 18ff12a66788766bca49330790415c27b97591af Mon Sep 17 00:00:00 2001 From: elliotdotsol Date: Sun, 5 Apr 2026 19:53:37 +0700 Subject: [PATCH 08/12] update: websocket management overhaul --- openapi/polymarket.json | 2 +- openapi/webhooks.json | 12 + openapi/ws.json | 9506 +++++++++++++++++++++++++++++----- package.json | 4 +- scripts/check-routes.ts | 4 +- scripts/generate-ws-types.ts | 87 +- src/generated/polymarket.ts | 37 +- src/generated/webhooks.ts | 2 +- src/generated/ws.ts | 3140 ++++++++++- src/types/index.ts | 17 + src/types/ws-helpers.ts | 3 +- src/types/ws.ts | 29 +- src/ws.ts | 5 +- 13 files changed, 11379 insertions(+), 1469 deletions(-) diff --git a/openapi/polymarket.json b/openapi/polymarket.json index cca6ace..8893c82 100644 --- a/openapi/polymarket.json +++ b/openapi/polymarket.json @@ -1 +1 @@ -{"openapi":"3.1.0","info":{"title":"Polymarket API","description":"RESTful API for querying Polymarket prediction markets data including events, markets, traders, holders, and real-time metrics","license":{"name":""},"version":"1.0.0"},"servers":[{"url":"https://api.struct.to/v1","description":"Production"}],"paths":{"/polymarket/asset-history":{"get":{"tags":["Assets"],"summary":"Get Asset Price History","description":"Returns historical price data for supported crypto assets from Polymarket API","operationId":"get_asset_history","parameters":[{"name":"asset_symbol","in":"query","description":"Asset ticker: BTC, ETH, XRP, SOL, DOGE, BNB, HYPE","required":true,"schema":{"type":"string"},"example":"BTC"},{"name":"variant","in":"query","description":"Time window: 5m, 15m, 1h, 4h, 1d","required":true,"schema":{"type":"string"},"example":"1h"},{"name":"from","in":"query","description":"Start timestamp in seconds (Unix epoch, inclusive)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp in seconds (Unix epoch, inclusive)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"limit","in":"query","description":"Number of results (default: 10, max: 100)","required":false,"schema":{"type":"integer","format":"int64"},"example":10}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AssetPriceHistoryRow"}}}}},"400":{"description":"Bad request - missing or invalid parameters"},"500":{"description":"Internal server error"}}}},"/polymarket/events":{"get":{"tags":["Events"],"summary":"Get events","description":"Retrieve a paginated list of events with filtering, sorting, and optional nested tags/markets","operationId":"get_events","parameters":[{"name":"id","in":"query","description":"Filter by event ID(s) - comma-separated (max 50). Cannot be used with 'event_slugs'. Example: id=99600,99601,99583","required":false,"schema":{"type":"string"}},{"name":"event_slugs","in":"query","description":"Filter by event slug(s) - comma-separated (max 50). Cannot be used with 'id'. Example: event_slugs=will-trump-win,bitcoin-100k","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","description":"Search in title and description (3-100 characters). Example: search=trump","required":false,"schema":{"type":"string"}},{"name":"sort_by","in":"query","description":"Sort: volume, txns, unique_traders, title, creation_date, start_date, end_date, relevance (relevance only works in search mode) (default: volume)","required":false,"schema":{"$ref":"#/components/schemas/EventSortBy"}},{"name":"sort_dir","in":"query","description":"Sort direction: asc, desc (default: desc)","required":false,"schema":{"$ref":"#/components/schemas/SortDirection"}},{"name":"timeframe","in":"query","description":"Metrics timeframe: 1m, 5m, 30m, 1h, 6h, 24h, 7d, 30d (default: 24h)","required":false,"schema":{"$ref":"#/components/schemas/MetricsTimeframe"}},{"name":"status","in":"query","description":"Filter by status: open, closed, or all (default: all)","required":false,"schema":{"$ref":"#/components/schemas/MarketStatus"}},{"name":"categories","in":"query","description":"Comma-separated category filters","required":false,"schema":{"type":"string"}},{"name":"exclude_categories","in":"query","description":"Comma-separated categories to exclude","required":false,"schema":{"type":"string"}},{"name":"tags","in":"query","description":"Filter by tag slug(s) - comma-separated (max 50). Example: tags=sports,football,crypto","required":false,"schema":{"type":"string"}},{"name":"exclude_tags","in":"query","description":"Comma-separated tag slugs to exclude","required":false,"schema":{"type":"string"}},{"name":"min_volume","in":"query","description":"Minimum volume in selected timeframe","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_volume","in":"query","description":"Maximum volume in selected timeframe","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_txns","in":"query","description":"Minimum transactions in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"max_txns","in":"query","description":"Maximum transactions in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"min_unique_traders","in":"query","description":"Minimum unique traders in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"max_unique_traders","in":"query","description":"Maximum unique traders in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"include_tags","in":"query","description":"Include tags array (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_markets","in":"query","description":"Include markets array with outcomes (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_metrics","in":"query","description":"Include metrics object with all timeframes (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key","required":false,"schema":{"type":"string"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of Polymarket events with nested tags, markets, and series. Response includes `pagination: { has_more, pagination_key }` for cursor-based pagination.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PolymarketEvent"}}}}},"400":{"description":"Bad request - validation error (search length, array limits, conflicting params)"}}}},"/polymarket/events/chart":{"get":{"tags":["Events"],"summary":"Get event chart","description":"Retrieve price data over time for up to 4 markets with highest YES outcome (outcome_index 0) prices in an event. Perfect for rendering multi-line charts showing price movement across top markets. TradingView-style: resolution parameter determines both candle size and implicit lookback period.","operationId":"get_event_chart","parameters":[{"name":"event_slug","in":"query","description":"Event slug (required)","required":true,"schema":{"type":"string"}},{"name":"condition_ids","in":"query","description":"Comma-separated condition IDs to include (max 4, optional)","required":false,"schema":{"type":"string"}},{"name":"market_slugs","in":"query","description":"Comma-separated market slugs to include (max 4, optional). Use either condition_ids or market_slugs, not both","required":false,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Time interval with implicit lookback: 1H (1 hour), 6H (6 hours), 1D (1 day), 1W (1 week), 1M (30 days), ALL (all data) (required)","required":true,"schema":{"type":"string","enum":["1H","6H","1D","1W","1M","ALL"]}}],"responses":{"200":{"description":"Price data over time for up to 4 markets with highest YES odds","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventMarketChartOutcome"}}}}}}}},"/polymarket/events/metrics":{"get":{"tags":["Events"],"summary":"Get event metrics","description":"Retrieve volume, transaction, and trader metrics for an event. Supports single timeframe (e.g., '1m'), multiple timeframes (e.g., '1m,5m,1h'), or 'all' to get all available timeframes.","operationId":"get_event_metrics","parameters":[{"name":"event_slug","in":"query","description":"Event slug","required":true,"schema":{"type":"string"}},{"name":"timeframe","in":"query","description":"Timeframe: single (1m, 5m, 30m, 1h, 6h, 24h, 7d, 30d), comma-separated (1m,5m,1h), or 'all'","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Event metrics for the specified timeframe(s). Returns single object for one timeframe, array for multiple.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventMetricsResponse"}}}},"400":{"description":"Invalid timeframe"}}}},"/polymarket/events/outcomes":{"get":{"tags":["Events"],"summary":"Get event market outcomes","description":"Returns the winning outcome name for each resolved market in an event, keyed by market slug. Useful for quickly checking which outcomes won across a series.","operationId":"get_event_outcomes","parameters":[{"name":"event_slug","in":"query","description":"Event slug (required)","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Number of resolved markets per page (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key for fetching next page","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Map of market_slug → winning outcome name with pagination metadata","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}}}}},"400":{"description":"Missing event_slug parameter"}}}},"/polymarket/events/slug/{slug}":{"get":{"tags":["Events"],"summary":"Get event by slug","description":"Retrieve a single event by its slug with optional nested tags, markets, and metrics","operationId":"get_event_by_slug","parameters":[{"name":"slug","in":"path","description":"Event slug","required":true,"schema":{"type":"string"}},{"name":"include_tags","in":"query","description":"Include tags array (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_markets","in":"query","description":"Include markets array with outcomes (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_metrics","in":"query","description":"Include metrics object with all timeframes (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Event with nested tags, markets, and series","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PolymarketEvent"}}}},"404":{"description":"Event not found"}}}},"/polymarket/events/{identifier}":{"get":{"tags":["Events"],"summary":"Get event by ID or slug","description":"Retrieve a single event by its numeric ID or slug with optional nested tags, markets, and metrics","operationId":"get_event","parameters":[{"name":"identifier","in":"path","description":"Event ID or slug","required":true,"schema":{"type":"string"}},{"name":"include_tags","in":"query","description":"Include tags array (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_markets","in":"query","description":"Include markets array with outcomes (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_metrics","in":"query","description":"Include metrics object with all timeframes (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Event with nested tags, markets, and series","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PolymarketEvent"}}}},"404":{"description":"Event not found"}}}},"/polymarket/holders/markets":{"get":{"tags":["Holders"],"summary":"Get market holders","description":"Retrieve holders of a market grouped by outcome, sorted by shares held. Identify the market with either `condition_id` or `market_slug` — exactly one must be provided. Set `include_pnl=true` to include a nested holder `pnl` object.","operationId":"get_market_holders","parameters":[{"name":"condition_id","in":"query","description":"Market condition ID (0x-prefixed hex)","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (e.g. `will-trump-win`)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"min_shares","in":"query","description":"Minimum shares held (decimal string)","required":false,"schema":{"type":"string"}},{"name":"max_shares","in":"query","description":"Maximum shares held (decimal string)","required":false,"schema":{"type":"string"}},{"name":"include_pnl","in":"query","description":"Include nested holder PnL data (default: false, +1 credit)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Market holders grouped by outcome (sorted by shares DESC). Holder `pnl` is included only when `include_pnl=true`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarketHoldersResponse"}}}},"404":{"description":"Market not found"}}}},"/polymarket/holders/markets/history":{"get":{"tags":["Holders"],"summary":"Get market holders history","description":"Retrieve historical holder count snapshots for a market over a time range. Identify the market with either `condition_id` or `market_slug` — exactly one must be provided.","operationId":"get_market_holders_history","parameters":[{"name":"condition_id","in":"query","description":"Market condition ID (0x-prefixed hex)","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (e.g. `will-trump-win`)","required":false,"schema":{"type":"string"}},{"name":"hours","in":"query","description":"Time range in hours (default: 24, max: 336 = 14 days)","required":false,"schema":{"type":"number","format":"double"}}],"responses":{"200":{"description":"Market holder count history with automatic granularity (1m/5m/15m/1h/6h buckets)","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/HolderHistoryCandle"}}}}},"404":{"description":"Market not found"}}}},"/polymarket/holders/positions/{position_id}":{"get":{"tags":["Holders"],"summary":"Get position holders","description":"Retrieve holders of a specific position (ERC1155 token), sorted by shares held. Set `include_pnl=true` to include nested holder PnL. Uses cursor-based pagination for efficient traversal.","operationId":"get_position_holders","parameters":[{"name":"position_id","in":"path","description":"Position ID (ERC1155 token ID)","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key","required":false,"schema":{"type":"string"}},{"name":"min_shares","in":"query","description":"Minimum shares held (decimal string)","required":false,"schema":{"type":"string"}},{"name":"max_shares","in":"query","description":"Maximum shares held (decimal string)","required":false,"schema":{"type":"string"}},{"name":"include_pnl","in":"query","description":"Include nested holder PnL data (default: false, +1 credit)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Position holders (sorted by shares DESC). Holder `pnl` is included only when `include_pnl=true`. Response includes `pagination: { has_more, pagination_key }` for cursor-based pagination.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PositionHoldersResponse"}}}},"404":{"description":"Position not found"}}}},"/polymarket/holders/positions/{position_id}/history":{"get":{"tags":["Holders"],"summary":"Get position holders history","description":"Retrieve historical holder count snapshots for a position over a time range","operationId":"get_position_holders_history","parameters":[{"name":"position_id","in":"path","description":"Position ID (ERC1155 token ID)","required":true,"schema":{"type":"string"}},{"name":"hours","in":"query","description":"Time range in hours (default: 24, max: 336 = 14 days)","required":false,"schema":{"type":"number","format":"double"}}],"responses":{"200":{"description":"Position holder count history with automatic granularity (1m/5m/15m/1h/6h buckets)","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/HolderHistoryCandle"}}}}},"404":{"description":"Position not found"}}}},"/polymarket/market":{"get":{"tags":["Market"],"summary":"Get markets","description":"Retrieve a paginated list of markets with filtering, sorting, and optional nested tags/events/metrics","operationId":"list_markets","parameters":[{"name":"condition_ids","in":"query","description":"Filter by condition ID(s) - comma-separated (max 50)","required":false,"schema":{"type":"string"}},{"name":"question_ids","in":"query","description":"Filter by question ID(s) - comma-separated (max 50)","required":false,"schema":{"type":"string"}},{"name":"market_ids","in":"query","description":"Filter by market ID(s) - comma-separated (max 50)","required":false,"schema":{"type":"string"}},{"name":"market_slugs","in":"query","description":"Filter by market slug(s) - comma-separated (max 50)","required":false,"schema":{"type":"string"}},{"name":"event_slugs","in":"query","description":"Filter by event slug(s) - comma-separated (max 50)","required":false,"schema":{"type":"string"}},{"name":"position_ids","in":"query","description":"Filter by position ID(s) - comma-separated (max 50)","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","description":"Search in title (3-100 characters)","required":false,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Filter by status: open, closed, or all (default: all)","required":false,"schema":{"$ref":"#/components/schemas/MarketStatus"}},{"name":"sort_by","in":"query","description":"Sort: volume, txns, unique_traders, liquidity, holders, end_time, start_time, created_time, relevance","required":false,"schema":{"$ref":"#/components/schemas/MarketSortBy"}},{"name":"sort_dir","in":"query","description":"Sort direction: asc, desc (default: desc)","required":false,"schema":{"$ref":"#/components/schemas/SortDirection"}},{"name":"timeframe","in":"query","description":"Metrics timeframe: 1m, 5m, 30m, 1h, 6h, 24h, 7d, 30d (default: 24h)","required":false,"schema":{"$ref":"#/components/schemas/MetricsTimeframe"}},{"name":"min_volume","in":"query","description":"Minimum total volume USD","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_volume","in":"query","description":"Maximum total volume USD","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_liquidity","in":"query","description":"Minimum liquidity USD","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_liquidity","in":"query","description":"Maximum liquidity USD","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_txns","in":"query","description":"Minimum transactions in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"max_txns","in":"query","description":"Maximum transactions in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"min_unique_traders","in":"query","description":"Minimum unique traders in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"max_unique_traders","in":"query","description":"Maximum unique traders in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"min_holders","in":"query","description":"Minimum total holders","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"max_holders","in":"query","description":"Maximum total holders","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"categories","in":"query","description":"Comma-separated category filters (max 50)","required":false,"schema":{"type":"string"}},{"name":"exclude_categories","in":"query","description":"Comma-separated categories to exclude","required":false,"schema":{"type":"string"}},{"name":"tags","in":"query","description":"Filter by tag(s) - comma-separated (max 50)","required":false,"schema":{"type":"string"}},{"name":"exclude_tags","in":"query","description":"Comma-separated tags to exclude","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Filter markets with end_time >= start_time (Unix timestamp)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"end_time","in":"query","description":"Filter markets with end_time <= end_time (Unix timestamp)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"include_tags","in":"query","description":"Include tags array (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_event","in":"query","description":"Include event object (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_metrics","in":"query","description":"Include all timeframe metrics (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key","required":false,"schema":{"type":"string"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of markets with metadata, outcomes, tags, event, and metrics. Response includes `pagination: { has_more, pagination_key }` for cursor-based pagination.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MarketResponse"}}}}},"400":{"description":"Bad request - validation error (search length, array limits, conflicting params)"}}}},"/polymarket/market/bonds":{"get":{"tags":["Bonds"],"summary":"Get bonds","description":"Retrieve a list of bond markets sorted by yield, filtered by probability and time to expiry","operationId":"get_bonds","parameters":[{"name":"min_probability","in":"query","description":"Minimum probability threshold (default: 0.85)","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_hours","in":"query","description":"Maximum hours until market end","required":false,"schema":{"type":"number","format":"double"}},{"name":"limit","in":"query","description":"Number of results (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor for pagination: end_date (unix epoch) of the last item from the previous page","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"List of bond markets sorted by yield","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BondMarket"}}}}}}}},"/polymarket/market/candlestick":{"get":{"tags":["Market"],"summary":"Get market candlesticks by condition_id","description":"Retrieve OHLCV candlestick data for a market by its condition_id","operationId":"get_market_candlestick","parameters":[{"name":"condition_id","in":"query","description":"Market condition ID (required)","required":true,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Candle interval: 1, 5, 15, 30, 60, 240, D, 1D","required":true,"schema":{"$ref":"#/components/schemas/CandlestickResolution"}},{"name":"count_back","in":"query","description":"Number of candles (max: 2500)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"from","in":"query","description":"Start timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"OHLCV candlestick data","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PredictionCandlestickBar"}}}}}}}},"/polymarket/market/chart":{"get":{"tags":["Market"],"summary":"Get market chart","description":"Retrieve price data over time for up to 4 position outcomes in a market condition. TradingView-style: resolution parameter determines both candle size and implicit lookback period. Auto-selects the 4 most active outcomes if position_ids not specified.","operationId":"get_chart","parameters":[{"name":"condition_id","in":"query","description":"Market condition ID or market_slug (one required)","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (alternative to condition_id)","required":false,"schema":{"type":"string"}},{"name":"position_ids","in":"query","description":"Comma-separated list of position IDs (max 4, optional). Auto-selected if not provided","required":false,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Time interval with implicit lookback: 1H (1 hour), 6H (6 hours), 1D (1 day), 1W (1 week), 1M (30 days), ALL (all data) (required)","required":true,"schema":{"type":"string","enum":["1H","6H","1D","1W","1M","ALL"]}}],"responses":{"200":{"description":"Price data over time for up to 4 market outcomes","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PositionChartOutcome"}}}}}}}},"/polymarket/market/metrics":{"get":{"tags":["Market"],"summary":"Get market metrics","description":"Retrieve volume, transaction, and trader metrics for a market. Supports single timeframe (e.g., '1m'), multiple timeframes (e.g., '1m,5m,1h'), or 'all' to get all available timeframes.","operationId":"get_market_metrics","parameters":[{"name":"condition_id","in":"query","description":"Market condition ID","required":true,"schema":{"type":"string"}},{"name":"timeframe","in":"query","description":"Timeframe: single (1m, 5m, 30m, 1h, 6h, 24h, 7d, 30d), comma-separated (1m,5m,1h), or 'all'","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Market metrics for the specified timeframe(s). Returns single object for one timeframe, array for multiple.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConditionMetricsResponse"}}}},"400":{"description":"Invalid timeframe"}}}},"/polymarket/market/position/candlestick":{"get":{"tags":["Market"],"summary":"Get position candlesticks by position_id","description":"Retrieve OHLCV candlestick data for a specific position by its position_id","operationId":"get_position_candlestick","parameters":[{"name":"position_id","in":"query","description":"Position/token ID (required)","required":true,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Candle interval: 1, 5, 15, 30, 60, 240, D, 1D","required":true,"schema":{"$ref":"#/components/schemas/CandlestickResolution"}},{"name":"count_back","in":"query","description":"Number of candles (max: 2500)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"from","in":"query","description":"Start timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"OHLCV candlestick data","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PredictionCandlestickBar"}}}}}}}},"/polymarket/market/position/metrics":{"get":{"tags":["Market"],"summary":"Get position metrics","description":"Retrieve volume, transaction, and trader metrics for a specific position. Supports single timeframe (e.g., '1m'), multiple timeframes (e.g., '1m,5m,1h'), or 'all' to get all available timeframes.","operationId":"get_position_metrics","parameters":[{"name":"position_id","in":"query","description":"Position/token ID","required":true,"schema":{"type":"string"}},{"name":"timeframe","in":"query","description":"Timeframe: single (1m, 5m, 30m, 1h, 6h, 24h, 7d, 30d), comma-separated (1m,5m,1h), or 'all'","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Position metrics for the specified timeframe(s). Returns single object for one timeframe, array for multiple.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PositionMetricsResponse"}}}},"400":{"description":"Invalid timeframe"}}}},"/polymarket/market/position/volume-chart":{"get":{"tags":["Market"],"summary":"Get position volume chart","description":"Retrieve volume over time for a specific position with buy/sell breakdown","operationId":"get_position_volume_chart","parameters":[{"name":"position_id","in":"query","description":"Position/token ID (required)","required":true,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Time interval: 1, 5, 15, 30, 60, 240, D, 1D (default: 60)","required":false,"schema":{"$ref":"#/components/schemas/CandlestickResolution"}},{"name":"count_back","in":"query","description":"Number of data points (max: 2500)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"from","in":"query","description":"Start timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Volume with buy/sell breakdown over time","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PositionVolumeDataPoint"}}}}}}}},"/polymarket/market/price-jumps":{"get":{"tags":["Market"],"summary":"Detect price jumps","description":"Scan candles for significant price movements. Returns jumps with from/to timestamps in milliseconds, directly usable as trades API time range parameters to identify traders who traded before or during the movement.","operationId":"get_price_jumps","parameters":[{"name":"condition_id","in":"query","description":"Market condition ID (one of condition_id or market_slug required)","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (resolved to condition_id)","required":false,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Candle resolution in minutes: 1, 5, 15, 30, 60, 240 (default: 15)","required":false,"schema":{"type":"string"}},{"name":"min_change_pct","in":"query","description":"Minimum relative percent change to qualify as a jump (default: 10.0)","required":false,"schema":{"type":"number","format":"double"}},{"name":"lookback","in":"query","description":"Number of candles to scan back from now (default: 1440, max: 2500)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"offset","in":"query","description":"Offset in candles from now — window is [now - (lookback + offset) * resolution, now - offset * resolution] (default: 0)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Price jumps sorted by timestamp descending","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PriceJump"}}}}}}}},"/polymarket/market/slug/{slug}":{"get":{"tags":["Market"],"summary":"Get market by slug","description":"Retrieve a single market by its slug with optional nested tags, event, and metrics","operationId":"get_market_by_slug","parameters":[{"name":"slug","in":"path","description":"Market slug (e.g. `will-trump-win`)","required":true,"schema":{"type":"string"}},{"name":"include_tags","in":"query","description":"Include tags array (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_event","in":"query","description":"Include event object (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_metrics","in":"query","description":"Include all timeframe metrics (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Market with metadata, outcomes, tags, event, and metrics","content":{"application/json":{"schema":{"type":"object","description":"Formatted market response with structured metrics, tags, outcomes, and event","required":["condition_id","status"],"properties":{"condition_id":{"type":"string"},"id":{"type":["string","null"]},"market_slug":{"type":["string","null"]},"question":{"type":["string","null"]},"title":{"type":["string","null"]},"description":{"type":["string","null"]},"image_url":{"type":["string","null"]},"oracle":{"type":["string","null"]},"status":{"type":"string"},"created_time":{"type":["integer","null"],"format":"int64"},"start_time":{"type":["integer","null"],"format":"int64"},"game_start_time":{"type":["integer","null"],"format":"int64"},"closed_time":{"type":["integer","null"],"format":"int64"},"end_time":{"type":["integer","null"],"format":"int64"},"accepting_orders":{"type":["boolean","null"]},"uma_resolution_status":{"type":["string","null"]},"is_neg_risk":{"type":["boolean","null"]},"market_maker_address":{"type":["string","null"]},"creator":{"type":["string","null"]},"category":{"type":["string","null"]},"volume_usd":{"type":["number","null"],"format":"double"},"liquidity_usd":{"type":["number","null"],"format":"double"},"highest_probability":{"type":["number","null"],"format":"double"},"total_holders":{"type":["integer","null"],"format":"int64"},"winning_outcome":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/MarketOutcome"}]},"outcomes":{"type":"array","items":{"$ref":"#/components/schemas/MarketOutcome"}},"rewards":{"type":"array","items":{"$ref":"#/components/schemas/MarketReward"}},"clob_rewards":{"type":"array","items":{"$ref":"#/components/schemas/ClobReward"}},"tags":{"type":"array","items":{"type":"string"}},"event_slug":{"type":["string","null"]},"resolution_source":{"type":["string","null"]},"metrics":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/SimpleTimeframeMetrics"},"propertyNames":{"type":"string"}},"relevance_score":{"type":["number","null"],"format":"double"}}}}}},"404":{"description":"Market not found"}}}},"/polymarket/market/trades":{"get":{"tags":["Market"],"summary":"Get market trades","description":"Retrieve trades for one or more markets, with filtering by trader, side, price, amount, and time range","operationId":"get_market_trades","parameters":[{"name":"condition_ids","in":"query","description":"Comma-separated condition IDs (max 20)","required":false,"schema":{"type":"string"}},{"name":"slugs","in":"query","description":"Comma-separated market slugs","required":false,"schema":{"type":"string"}},{"name":"position_ids","in":"query","description":"Comma-separated position IDs","required":false,"schema":{"type":"string"}},{"name":"traders","in":"query","description":"Comma-separated trader addresses (max 25)","required":false,"schema":{"type":"string"}},{"name":"side","in":"query","description":"Trade side: 0 (Buy), 1 (Sell)","required":false,"schema":{"$ref":"#/components/schemas/TradeSide"}},{"name":"outcome","in":"query","description":"Outcome name filter (e.g. Yes, No)","required":false,"schema":{"type":"string"}},{"name":"outcome_index","in":"query","description":"Outcome index: 0 (Yes), 1 (No)","required":false,"schema":{"$ref":"#/components/schemas/OutcomeIndex"}},{"name":"trade_type","in":"query","description":"Trade type: 0 (OrderFilled), 1 (Redemption), 2 (Merge)","required":false,"schema":{"$ref":"#/components/schemas/TradeType"}},{"name":"min_usd_amount","in":"query","description":"Min USD amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_usd_amount","in":"query","description":"Max USD amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_shares_amount","in":"query","description":"Min shares amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_shares_amount","in":"query","description":"Max shares amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_price","in":"query","description":"Min price (0.0-1.0)","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_price","in":"query","description":"Max price (0.0-1.0)","required":false,"schema":{"type":"number","format":"double"}},{"name":"from","in":"query","description":"Start timestamp (ms)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (ms)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"all","in":"query","description":"Return all-time trades, not just last 30 days (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Results per page (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32","minimum":0}},{"name":"pagination_key","in":"query","description":"Offset-based pagination key (integer offset into result set)","required":false,"schema":{"type":"integer","format":"int32","minimum":0}},{"name":"sort_desc","in":"query","description":"Sort newest first (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Prediction trades matching filters","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PredictionTradeResponse"}}}}}}}},"/polymarket/market/volume-chart":{"get":{"tags":["Market"],"summary":"Get market volume chart","description":"Retrieve volume breakdown by YES/NO outcome over time for a prediction market","operationId":"get_market_volume_chart","parameters":[{"name":"condition_id","in":"query","description":"Market condition ID (or use market_slug)","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (alternative to condition_id)","required":false,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Time interval: 1, 5, 15, 30, 60, 240, D, 1D (default: 60)","required":false,"schema":{"$ref":"#/components/schemas/CandlestickResolution"}},{"name":"count_back","in":"query","description":"Number of data points (max: 2500)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"from","in":"query","description":"Start timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Volume breakdown by YES/NO over time","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MarketVolumeDataPoint"}}}}}}}},"/polymarket/market/{condition_id}":{"get":{"tags":["Market"],"summary":"Get market by condition ID","description":"Retrieve a single market by its condition ID with optional nested tags, event, and metrics","operationId":"get_market","parameters":[{"name":"condition_id","in":"path","description":"Market condition ID (0x-prefixed hex)","required":true,"schema":{"type":"string"}},{"name":"include_tags","in":"query","description":"Include tags array (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_event","in":"query","description":"Include event object (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_metrics","in":"query","description":"Include all timeframe metrics (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Market with metadata, outcomes, tags, event, and metrics","content":{"application/json":{"schema":{"type":"object","description":"Formatted market response with structured metrics, tags, outcomes, and event","required":["condition_id","status"],"properties":{"condition_id":{"type":"string"},"id":{"type":["string","null"]},"market_slug":{"type":["string","null"]},"question":{"type":["string","null"]},"title":{"type":["string","null"]},"description":{"type":["string","null"]},"image_url":{"type":["string","null"]},"oracle":{"type":["string","null"]},"status":{"type":"string"},"created_time":{"type":["integer","null"],"format":"int64"},"start_time":{"type":["integer","null"],"format":"int64"},"game_start_time":{"type":["integer","null"],"format":"int64"},"closed_time":{"type":["integer","null"],"format":"int64"},"end_time":{"type":["integer","null"],"format":"int64"},"accepting_orders":{"type":["boolean","null"]},"uma_resolution_status":{"type":["string","null"]},"is_neg_risk":{"type":["boolean","null"]},"market_maker_address":{"type":["string","null"]},"creator":{"type":["string","null"]},"category":{"type":["string","null"]},"volume_usd":{"type":["number","null"],"format":"double"},"liquidity_usd":{"type":["number","null"],"format":"double"},"highest_probability":{"type":["number","null"],"format":"double"},"total_holders":{"type":["integer","null"],"format":"int64"},"winning_outcome":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/MarketOutcome"}]},"outcomes":{"type":"array","items":{"$ref":"#/components/schemas/MarketOutcome"}},"rewards":{"type":"array","items":{"$ref":"#/components/schemas/MarketReward"}},"clob_rewards":{"type":"array","items":{"$ref":"#/components/schemas/ClobReward"}},"tags":{"type":"array","items":{"type":"string"}},"event_slug":{"type":["string","null"]},"resolution_source":{"type":["string","null"]},"metrics":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/SimpleTimeframeMetrics"},"propertyNames":{"type":"string"}},"relevance_score":{"type":["number","null"],"format":"double"}}}}}},"404":{"description":"Market not found"}}}},"/polymarket/order-book":{"get":{"tags":["Order Book"],"summary":"Get order book","description":"Returns the latest CLOB orderbook snapshot for a position, including derived metrics (best bid/ask, mid price, spread, liquidity depth). Data is sourced from the real-time Polymarket WebSocket feed. `bids` and `asks` are arrays of `{\"p\": price, \"s\": size}` objects, sorted best-first.","operationId":"get_order_book","parameters":[{"name":"position_id","in":"query","description":"Token ID (position ID) to query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Latest orderbook snapshot. ts is Unix milliseconds.","content":{"application/json":{"schema":{"type":"object","required":["ts","position_id","condition_id","bids","asks","hash"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"bids":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"asks":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"hash":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}}}}},"400":{"description":"Missing or invalid parameters"}}}},"/polymarket/order-book/history":{"get":{"tags":["Order Book"],"summary":"Get order book history","description":"Paginated history of raw CLOB orderbook snapshots including full bids/asks levels and derived metrics. Default limit 20, max 200. `bids` and `asks` are arrays of `{\"p\": price, \"s\": size}` objects, sorted best-first.","operationId":"get_order_book_history","parameters":[{"name":"position_id","in":"query","description":"Token ID (required if condition_id / market_slug not set)","required":false,"schema":{"type":"string"}},{"name":"condition_id","in":"query","description":"Condition ID — returns history for all positions in this market","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (alternative to condition_id)","required":false,"schema":{"type":"string"}},{"name":"from","in":"query","description":"Start timestamp (Unix milliseconds, inclusive)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (Unix milliseconds, inclusive)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"min_spread","in":"query","description":"Only return snapshots with spread >= this value","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_spread","in":"query","description":"Only return snapshots with spread <= this value","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_liquidity","in":"query","description":"Only return snapshots where total liquidity (bid + ask) >= this value","required":false,"schema":{"type":"number","format":"double"}},{"name":"limit","in":"query","description":"Number of results (default: 20, max: 200)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"pagination_key","in":"query","description":"Cursor from previous response's pagination.pagination_key","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Orderbook snapshot rows, newest first. ts is Unix milliseconds.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","required":["ts","position_id","condition_id","bids","asks","hash"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"bids":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"asks":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"hash":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}}}}}},"400":{"description":"Missing or invalid parameters"}}}},"/polymarket/order-book/market":{"get":{"tags":["Order Book"],"summary":"Get order books for a market","description":"Returns the latest orderbook snapshot for every position (outcome) in a market. Accepts condition_id or market_slug. `bids` and `asks` are arrays of `{\"p\": price, \"s\": size}` objects, sorted best-first.","operationId":"get_market_order_book","parameters":[{"name":"condition_id","in":"query","description":"Condition ID of the market","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (alternative to condition_id)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Latest orderbook snapshot per position. ts is Unix milliseconds.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","required":["ts","position_id","condition_id","bids","asks","hash"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"bids":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"asks":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"hash":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}}}}}},"400":{"description":"Missing or invalid parameters"}}}},"/polymarket/order-book/spread":{"get":{"tags":["Order Book"],"summary":"Get spread history","description":"Lightweight time series of derived orderbook metrics (best bid/ask, mid price, spread, liquidity depth) without raw bids/asks — ideal for charting. Default limit 20, max 200.","operationId":"get_spread_history","parameters":[{"name":"position_id","in":"query","description":"Token ID (required if condition_id / market_slug not set)","required":false,"schema":{"type":"string"}},{"name":"condition_id","in":"query","description":"Condition ID — returns spread history for all positions in this market","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (alternative to condition_id)","required":false,"schema":{"type":"string"}},{"name":"from","in":"query","description":"Start timestamp (Unix milliseconds, inclusive)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (Unix milliseconds, inclusive)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"min_spread","in":"query","description":"Only return rows with spread >= this value","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_spread","in":"query","description":"Only return rows with spread <= this value","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_liquidity","in":"query","description":"Only return rows where total liquidity (bid + ask) >= this value","required":false,"schema":{"type":"number","format":"double"}},{"name":"limit","in":"query","description":"Number of results (default: 100, max: 1000)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"pagination_key","in":"query","description":"Cursor from previous response's pagination.pagination_key","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Spread time series rows, newest first. ts is Unix milliseconds.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","description":"Lightweight row — derived metrics only, no bids/asks JSONB.","required":["ts","position_id","condition_id"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}}}}}},"400":{"description":"Missing or invalid parameters"}}}},"/polymarket/search":{"get":{"tags":["Search"],"summary":"Search events, markets, and traders","description":"Search across markets, events, and traders. Use `type` to limit which categories are searched. Trader search supports wallet address lookup or name search. Results for each category are independently paginated. Only requested categories are included in the response.","operationId":"search","parameters":[{"name":"q","in":"query","description":"Search query (min 2 characters). Prefix with 0x for exact wallet address lookup.","required":true,"schema":{"type":"string"}},{"name":"type","in":"query","description":"Comma-separated categories to search: events, markets, traders (default: all three, 1 credit per type). Example: type=markets,traders","required":false,"schema":{"type":"string"}},{"name":"include_pnl","in":"query","description":"Include lifetime PnL summary for each trader (default: false, +1 credit)","required":false,"schema":{"type":"boolean"}},{"name":"sort_by","in":"query","description":"Sort field applied to both events and markets (default: volume). Fields marked events-only or markets-only fall back to volume on the other category.","required":false,"schema":{"$ref":"#/components/schemas/SearchSortBy"}},{"name":"sort_dir","in":"query","description":"Sort direction (default: desc)","required":false,"schema":{"$ref":"#/components/schemas/SortDirection"}},{"name":"timeframe","in":"query","description":"Metrics timeframe used for volume/txns/unique_traders sort (default: 24h)","required":false,"schema":{"$ref":"#/components/schemas/MetricsTimeframe"}},{"name":"limit","in":"query","description":"Results limit per category (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"events_pagination_key","in":"query","description":"Cursor for the next page of events, obtained from previous response's events_pagination.pagination_key","required":false,"schema":{"type":"string"}},{"name":"markets_pagination_key","in":"query","description":"Cursor for the next page of markets, obtained from previous response's markets_pagination.pagination_key","required":false,"schema":{"type":"string"}},{"name":"traders_pagination_key","in":"query","description":"Cursor for the next page of traders, obtained from previous response's traders_pagination.pagination_key","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Search results. Only requested categories (via `type`) are included in the response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchResponse"}}}},"400":{"description":"Bad request — q is missing or shorter than 2 characters"}}}},"/polymarket/series":{"get":{"tags":["Series"],"summary":"List or get series","description":"Retrieve series. Use `id` or `series_slug` for single lookup, `series_ids` or `series_slugs` (comma-separated, max 250, mutually exclusive) for multi-lookup, or paginate with `active_only`.","operationId":"get_series_list","parameters":[{"name":"id","in":"query","description":"Single series ID for direct lookup","required":false,"schema":{"type":"string"}},{"name":"series_ids","in":"query","description":"Comma-separated series IDs (max 250). Mutually exclusive with series_slugs.","required":false,"schema":{"type":"string"}},{"name":"series_slugs","in":"query","description":"Comma-separated series slugs (max 250). Mutually exclusive with series_ids.","required":false,"schema":{"type":"string"}},{"name":"active_only","in":"query","description":"Only active series (default: true). Ignored when series_ids or series_slugs are provided.","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor for pagination: id of the last series from the previous page","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Series or list of series","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PolymarketSeries"}}}}},"400":{"description":"series_ids and series_slugs cannot both be provided"}}}},"/polymarket/series/outcomes":{"get":{"tags":["Series"],"summary":"Get series market outcomes","description":"Returns the winning outcome name for each resolved market across all events in a series, keyed by market slug. Useful for checking historical results across recurring series (e.g., btc-updown-5m).","operationId":"get_series_outcomes","parameters":[{"name":"series_slug","in":"query","description":"Series slug (required)","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Number of resolved markets per page (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key for fetching next page","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Map of market_slug → winning outcome name with pagination metadata","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}}}}},"400":{"description":"Missing series_slug parameter"}}}},"/polymarket/tags":{"get":{"tags":["Tags"],"summary":"Get tags","description":"Retrieve all available event tags/categories. Uses cursor-based pagination for efficient traversal.","operationId":"get_tags","parameters":[{"name":"limit","in":"query","description":"Results limit (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of all tags","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PolymarketTag"}}}}}}}},"/polymarket/tags/{identifier}":{"get":{"tags":["Tags"],"summary":"Get tag by slug","description":"Retrieve a single tag by its ID or slug","operationId":"get_tag_by_id","parameters":[{"name":"identifier","in":"path","description":"Tag ID or slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Tag details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PolymarketTag"}}}},"404":{"description":"Tag not found"}}}},"/polymarket/trader/global_pnl":{"get":{"tags":["Trader"],"summary":"Get global leaderboard","description":"Retrieve the global PnL leaderboard ranked by profit and loss. Uses cursor-based pagination for efficient traversal of large datasets.","operationId":"get_global_pnl","parameters":[{"name":"timeframe","in":"query","description":"Timeframe: 1d, 7d, 30d, lifetime (default: lifetime)","required":false,"schema":{"$ref":"#/components/schemas/PnlTimeframe"}},{"name":"sort_by","in":"query","description":"Sort: realized_pnl_usd, buys, sells, redemptions, merges, avg_hold_time, markets_traded, events_traded, markets_won, volume_usd, fees, best_trade (default: realized_pnl_usd)","required":false,"schema":{"$ref":"#/components/schemas/GlobalPnlSortBy"}},{"name":"sort_direction","in":"query","description":"Sort direction: asc, desc (default: desc)","required":false,"schema":{"$ref":"#/components/schemas/SortDirection"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 200)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Global PnL leaderboard with trader stats. Response includes `pagination: { has_more, pagination_key }` for cursor-based pagination.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GlobalPnlTrader"}}}}}}}},"/polymarket/trader/pnl/{address}":{"get":{"tags":["Trader"],"summary":"Get trader PnL summary","description":"Retrieve a trader's overall profit and loss summary","operationId":"get_trader_pnl","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"timeframe","in":"query","description":"Timeframe: 1d, 7d, 30d, lifetime (default: lifetime)","required":false,"schema":{"$ref":"#/components/schemas/PnlTimeframe"}}],"responses":{"200":{"description":"Trader's global PnL summary","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TraderPnlSummary"}}}}}}},"/polymarket/trader/pnl/{address}/calendar":{"get":{"tags":["Trader"],"summary":"Get trader PnL calendar","description":"Retrieve raw per-day PnL. Each entry is the realized PnL for that calendar day. Paginate backwards using the pagination key.","operationId":"get_trader_pnl_calendar","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"days","in":"query","description":"Window size in days (default: 30, max: 30)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Pagination key obtained from a previous response to fetch an earlier window","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Daily PnL entries (one per active trading day)","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PnlCandleEntry"}}}}}}}},"/polymarket/trader/pnl/{address}/candles":{"get":{"tags":["Trader"],"summary":"Get trader PnL candles","description":"Retrieve PnL candles for charting a trader's equity curve over time.","operationId":"get_trader_pnl_candles","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Candle resolution (default: 1h)","required":false,"schema":{"$ref":"#/components/schemas/PnlCandleResolution"}},{"name":"timeframe","in":"query","description":"Time range (default: lifetime)","required":false,"schema":{"$ref":"#/components/schemas/PnlCandleTimeframe"}}],"responses":{"200":{"description":"Cumulative PnL candles","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PnlCandleEntry"}}}}}}}},"/polymarket/trader/pnl/{address}/events":{"get":{"tags":["Trader"],"summary":"Get trader event PnL","description":"Retrieve event-level PnL breakdown for a trader","operationId":"get_trader_event_pnl","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"timeframe","in":"query","description":"Timeframe: 1d, 7d, 30d, lifetime (default: lifetime)","required":false,"schema":{"$ref":"#/components/schemas/PnlTimeframe"}},{"name":"sort_by","in":"query","description":"Sort: realized_pnl_usd, total_volume_usd, markets_traded, total_fees (default: realized_pnl_usd)","required":false,"schema":{"$ref":"#/components/schemas/EventPnlSortBy"}},{"name":"sort_direction","in":"query","description":"Sort direction: asc, desc (default: desc)","required":false,"schema":{"$ref":"#/components/schemas/SortDirection"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 200)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"offset","in":"query","description":"Pagination offset (number of results to skip). Takes precedence over pagination_key.","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key obtained from previous response's pagination.pagination_key","required":false,"schema":{"type":"string"}},{"name":"event_slug","in":"query","description":"Filter by event slug","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Event-level PnL entries for this trader","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TraderEventPnlEntry"}}}}}}}},"/polymarket/trader/pnl/{address}/markets":{"get":{"tags":["Trader"],"summary":"Get trader market PnL","description":"Retrieve market-level PnL breakdown for a trader","operationId":"get_trader_market_pnl","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"timeframe","in":"query","description":"Timeframe: 1d, 7d, 30d, lifetime (default: lifetime)","required":false,"schema":{"$ref":"#/components/schemas/PnlTimeframe"}},{"name":"sort_by","in":"query","description":"Sort: realized_pnl_usd, buy_usd, total_buys, total_fees, outcomes_traded (default: realized_pnl_usd)","required":false,"schema":{"$ref":"#/components/schemas/MarketPnlSortBy"}},{"name":"sort_direction","in":"query","description":"Sort direction: asc, desc (default: desc)","required":false,"schema":{"$ref":"#/components/schemas/SortDirection"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 200)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"offset","in":"query","description":"Pagination offset (number of results to skip). Takes precedence over pagination_key.","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key obtained from previous response's pagination.pagination_key","required":false,"schema":{"type":"string"}},{"name":"condition_id","in":"query","description":"Filter by condition ID (or use market_slug)","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Filter by market slug (alternative to condition_id)","required":false,"schema":{"type":"string"}},{"name":"event_slug","in":"query","description":"Filter by event slug","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Market-level PnL entries for this trader","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TraderMarketPnlEntry"}}}}}}}},"/polymarket/trader/pnl/{address}/positions":{"get":{"tags":["Trader"],"summary":"Get trader position PnL","description":"Retrieve per-outcome-token lifetime PnL for a trader from polymarket_accounts. Includes open/closed state, win/loss outcome, redemption payouts, and share quantities. Filter by status and won/lost to segment portfolio views.","operationId":"get_trader_position_pnl","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Required. Filter by position status","required":true,"schema":{"type":"string","enum":["open","closed"]}},{"name":"won","in":"query","description":"Filter by outcome: true (won), false (lost), only for status=closed","required":false,"schema":{"type":"boolean"}},{"name":"search","in":"query","description":"Search by market title","required":false,"schema":{"type":"string"}},{"name":"sort_by","in":"query","description":"Sort field (default: realized_pnl_usd)","required":false,"schema":{"$ref":"#/components/schemas/PositionPnlSortBy"}},{"name":"sort_direction","in":"query","description":"Sort direction: asc, desc (default: desc)","required":false,"schema":{"$ref":"#/components/schemas/SortDirection"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 200)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"offset","in":"query","description":"Pagination offset","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"condition_id","in":"query","description":"Filter by market condition ID (or use market_slug)","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Filter by market slug (alternative to condition_id)","required":false,"schema":{"type":"string"}},{"name":"position_id","in":"query","description":"Filter by specific outcome token (position ID)","required":false,"schema":{"type":"string"}},{"name":"min_shares","in":"query","description":"Minimum shares balance to include (e.g. 1.0 to filter out dust positions)","required":false,"schema":{"type":"number","format":"double"}}],"responses":{"200":{"description":"Position-level PnL entries for this trader. Each entry is a specific outcome token with open/closed state, avg_entry_price, avg_exit_price, and redemption info.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TraderOutcomePnlEntry"}}}}}}}},"/polymarket/trader/profile/{address}":{"get":{"tags":["Trader"],"summary":"Get trader overview","description":"Retrieve a trader's profile including stats and trading history summary","operationId":"get_trader_profile","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Trader profile information with username, bio, and badges","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PolymarketUserProfile"}}}}}}},"/polymarket/trader/profiles/batch":{"get":{"tags":["Trader"],"summary":"Get multiple trader profiles","description":"Retrieve profiles for multiple traders in a single request. Returns an array of profiles.","operationId":"get_trader_profiles_batch","parameters":[{"name":"addresses","in":"query","description":"Comma-separated list of trader addresses (max: 20)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Array of trader profiles","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PolymarketUserProfile"}}}}},"400":{"description":"Invalid request (empty addresses or more than 20)"}}}},"/polymarket/trader/trades/{address}":{"get":{"tags":["Trader"],"summary":"Get trader trades","description":"Retrieve trade history for a specific trader across all markets","operationId":"get_trader_trades","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"condition_ids","in":"query","description":"Comma-separated condition IDs (max 20)","required":false,"schema":{"type":"string"}},{"name":"slugs","in":"query","description":"Comma-separated market slugs","required":false,"schema":{"type":"string"}},{"name":"position_ids","in":"query","description":"Comma-separated position IDs","required":false,"schema":{"type":"string"}},{"name":"side","in":"query","description":"Trade side: 0 (Buy), 1 (Sell)","required":false,"schema":{"$ref":"#/components/schemas/TradeSide"}},{"name":"outcome","in":"query","description":"Outcome name filter (e.g. Yes, No)","required":false,"schema":{"type":"string"}},{"name":"outcome_index","in":"query","description":"Outcome index: 0 (Yes), 1 (No)","required":false,"schema":{"$ref":"#/components/schemas/OutcomeIndex"}},{"name":"trade_type","in":"query","description":"Trade type: 0 (OrderFilled), 1 (Redemption), 2 (Merge)","required":false,"schema":{"$ref":"#/components/schemas/TradeType"}},{"name":"min_usd_amount","in":"query","description":"Min USD amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_usd_amount","in":"query","description":"Max USD amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_shares_amount","in":"query","description":"Min shares amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_shares_amount","in":"query","description":"Max shares amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_price","in":"query","description":"Min price (0.0-1.0)","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_price","in":"query","description":"Max price (0.0-1.0)","required":false,"schema":{"type":"number","format":"double"}},{"name":"from","in":"query","description":"Start timestamp (ms)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (ms)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"all","in":"query","description":"Return all-time trades, not just last 30 days (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Results per page (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32","minimum":0}},{"name":"offset","in":"query","description":"Pagination offset (number of results to skip). Takes precedence over pagination_key.","required":false,"schema":{"type":"integer","format":"int32","minimum":0}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key obtained from previous response's pagination.pagination_key","required":false,"schema":{"type":"string"}},{"name":"sort_desc","in":"query","description":"Sort newest first (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Trader's trade history with advanced filtering (same as /market/trades but filtered by trader)","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PredictionTradeResponse"}}}}}}}},"/polymarket/trader/volume-chart/{address}":{"get":{"tags":["Trader"],"summary":"Get trader volume chart","description":"Retrieve volume breakdown by buy/sell over time for a specific trader","operationId":"get_trader_volume_chart","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Time interval: 1, 5, 15, 30, 60, 240, D, 1D (default: 60)","required":false,"schema":{"$ref":"#/components/schemas/CandlestickResolution"}},{"name":"count_back","in":"query","description":"Number of data points (max: 2500)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"from","in":"query","description":"Start timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Trader volume with buy/sell breakdown over time","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TraderVolumeDataPoint"}}}}}}}}},"components":{"schemas":{"AssetPriceHistoryRow":{"type":"object","description":"A single asset price history record from the `asset_price_history` table.","required":["asset_symbol","asset_open_price","asset_close_price","variant","start_time","end_time"],"properties":{"asset_symbol":{"type":"string"},"asset_open_price":{"type":"number","format":"double","description":"Opening price at start_time (cast to f64 from NUMERIC in query)"},"asset_close_price":{"type":"number","format":"double","description":"Closing price at end_time (cast to f64 from NUMERIC in query)"},"price_change_percentage":{"type":["number","null"],"format":"double"},"outcome":{"type":["string","null"],"description":"Generated column: \"up\" if close > open, \"down\" if close ≤ open, null if no close yet"},"variant":{"type":"string","description":"Time window: \"5m\", \"15m\", \"1h\", \"1d\""},"start_time":{"type":"integer","format":"int64","description":"Window start timestamp (seconds since epoch)"},"end_time":{"type":"integer","format":"int64","description":"Window end timestamp (seconds since epoch)"}}},"AssetSymbol":{"type":"string","enum":["BTC","ETH","XRP","SOL","DOGE","BNB","HYPE"]},"AssetVariant":{"type":"string","enum":["5m","15m","1h","4h","1d"]},"BondMarket":{"type":"object","required":["condition_id","question","market_slug","end_time","best_outcome_index","return_pct","apy","outcomes"],"properties":{"condition_id":{"type":"string"},"title":{"type":["string","null"]},"question":{"type":"string"},"market_slug":{"type":"string"},"event_slug":{"type":["string","null"]},"image_url":{"type":["string","null"]},"end_time":{"type":"integer","format":"int64"},"best_outcome_index":{"type":"integer","format":"int32","minimum":0},"return_pct":{"type":"number","format":"double"},"apy":{"type":"number","format":"double"},"volume_24h":{"type":["number","null"],"format":"double"},"outcomes":{"type":"array","items":{"$ref":"#/components/schemas/BondOutcome"}}}},"BondOutcome":{"type":"object","required":["name","index","position_id","price"],"properties":{"name":{"type":"string"},"index":{"type":"integer","format":"int32"},"position_id":{"type":"string"},"price":{"type":"number","format":"double"}}},"CandlestickResolution":{"type":"string","enum":["1","5","15","30","60","240","D","1D"]},"ClobReward":{"type":"object","description":"CLOB reward (public API format)","required":["id","condition_id"],"properties":{"id":{"type":"string"},"condition_id":{"type":"string"},"asset_address":{"type":["string","null"]},"rewards_amount":{"type":["number","null"],"format":"double"},"rewards_daily_rate":{"type":["number","null"],"format":"double"},"start_date":{"type":["string","null"]},"end_date":{"type":["string","null"]}}},"ConditionMetricsResponse":{"type":"object","description":"Response type for condition metrics query","required":["condition_id","timeframe","volume_usd","fees","txns","unique_traders"],"properties":{"condition_id":{"type":"string"},"timeframe":{"type":"string"},"volume_usd":{"type":"number","format":"double"},"fees":{"type":"number","format":"double"},"txns":{"type":"integer","format":"int32"},"unique_traders":{"type":"integer","format":"int32"}}},"ConditionOrderbookRow":{"type":"object","required":["ts","position_id","condition_id","bids","asks","hash"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"bids":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"asks":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"hash":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}},"EventMarket":{"type":"object","description":"Enriched market data for event API responses","properties":{"condition_id":{"type":"string","default":""},"id":{"type":["string","null"],"default":null},"title":{"type":["string","null"],"default":null},"question":{"type":"string","default":""},"market_slug":{"type":"string","default":""},"status":{"type":"string","default":""},"created_time":{"type":["integer","null"],"format":"int64","default":null},"end_time":{"type":["integer","null"],"format":"int64","default":null},"volume":{"type":["number","null"],"format":"double","default":null},"liquidity_usd":{"type":["number","null"],"format":"double","default":null},"volume_24hr":{"type":["number","null"],"format":"double","default":null},"image_url":{"type":["string","null"],"default":null},"market_maker_address":{"type":["string","null"],"default":null},"creator":{"type":["string","null"],"default":null},"category":{"type":["string","null"],"default":null},"accepting_orders":{"type":["boolean","null"],"default":null},"uma_resolution_status":{"type":["string","null"],"default":null},"clob_rewards":{"type":"array","items":{"$ref":"#/components/schemas/ClobReward"},"default":[]},"outcomes":{"type":"array","items":{"$ref":"#/components/schemas/EventMarketOutcome"},"default":[]},"winning_outcome":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/EventMarketOutcome"}],"default":null}}},"EventMarketChartDataPoint":{"type":"object","required":["v","t"],"properties":{"v":{"type":"number","format":"double"},"t":{"type":"integer","format":"int64","minimum":0}}},"EventMarketChartOutcome":{"type":"object","required":["condition_id","market_slug","question","title","data"],"properties":{"condition_id":{"type":"string"},"market_slug":{"type":"string"},"question":{"type":"string"},"title":{"type":"string"},"data":{"type":"array","items":{"$ref":"#/components/schemas/EventMarketChartDataPoint"}}}},"EventMarketOutcome":{"type":"object","description":"Market outcome for event API responses","required":["name"],"properties":{"name":{"type":"string"},"price":{"type":["number","null"],"format":"double"},"position_id":{"type":["string","null"]},"outcome_index":{"type":["integer","null"],"format":"int32"}}},"EventMetricsResponse":{"type":"object","description":"Response type for event metrics query","required":["event_slug","timeframe","volume_usd","fees","txns","unique_traders"],"properties":{"event_slug":{"type":"string"},"timeframe":{"type":"string"},"volume_usd":{"type":"number","format":"double"},"fees":{"type":"number","format":"double"},"txns":{"type":"integer","format":"int32"},"unique_traders":{"type":"integer","format":"int32"}}},"EventPnlSortBy":{"type":"string","enum":["realized_pnl_usd","total_volume_usd","markets_traded","total_fees","realized_pnl_pct"]},"EventSortBy":{"type":"string","enum":["volume","txns","unique_traders","title","creation_date","start_date","end_date","relevance"]},"GlobalPnlSortBy":{"type":"string","enum":["realized_pnl_usd","buys","sells","redemptions","merges","avg_hold_time","markets_traded","events_traded","markets_won","volume_usd","fees","best_trade"]},"GlobalPnlTrader":{"type":"object","description":"Individual trader entry in the global PnL leaderboard","required":["trader"],"properties":{"trader":{"$ref":"#/components/schemas/TraderInfo"},"realized_pnl_usd":{"type":["number","null"],"format":"double"},"events_traded":{"type":["integer","null"],"format":"int64"},"markets_traded":{"type":["integer","null"],"format":"int64"},"markets_won":{"type":["integer","null"],"format":"int64"},"markets_lost":{"type":["integer","null"],"format":"int64"},"market_win_rate_pct":{"type":["number","null"],"format":"double"},"total_volume_usd":{"type":["number","null"],"format":"double"},"buy_volume_usd":{"type":["number","null"],"format":"double"},"sell_volume_usd":{"type":["number","null"],"format":"double"},"redemption_volume_usd":{"type":["number","null"],"format":"double"},"merge_volume_usd":{"type":["number","null"],"format":"double"},"total_buys":{"type":["integer","null"],"format":"int64"},"total_sells":{"type":["integer","null"],"format":"int64"},"total_redemptions":{"type":["integer","null"],"format":"int64"},"total_merges":{"type":["integer","null"],"format":"int64"},"total_trades":{"type":["integer","null"],"format":"int64"},"total_fees":{"type":["number","null"],"format":"double"},"avg_pnl_per_market":{"type":["number","null"],"format":"double"},"avg_pnl_per_trade":{"type":["number","null"],"format":"double"},"avg_hold_time_seconds":{"type":["number","null"],"format":"double"},"best_trade_pnl_usd":{"type":["number","null"],"format":"double"},"best_trade_condition_id":{"type":["string","null"]},"first_trade_at":{"type":["integer","null"],"format":"int64"},"last_trade_at":{"type":["integer","null"],"format":"int64"}}},"Holder":{"type":"object","description":"Individual holder data","required":["trader","shares"],"properties":{"trader":{"$ref":"#/components/schemas/Trader","description":"Trader profile information"},"shares":{"type":"string","description":"Position shares held (raw balance as string for precision)"},"shares_usd":{"type":["string","null"],"description":"USD value of shares (shares * latest price)"},"usd_balance":{"type":["string","null"],"description":"USD balance of wallet (USDe on Polygon)"},"pnl":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/HolderPnl","description":"Holder-level PnL, included only when `include_pnl=true`"}]}}},"HolderHistoryCandle":{"type":"object","description":"Holder statistics data point (single time bucket)","required":["t"],"properties":{"t":{"type":"integer","format":"int64"},"h":{"type":["integer","null"],"format":"int64"}}},"HolderPnl":{"type":"object","description":"Holder-level PnL data, included when `include_pnl=true`","properties":{"avg_entry_price":{"type":["number","null"],"format":"double"},"total_cost_usd":{"type":["string","null"]},"unrealized_pnl_usd":{"type":["string","null"]},"realized_sell_pnl_usd":{"type":["string","null"]},"avg_exit_price":{"type":["number","null"],"format":"double"},"buy_usd":{"type":["number","null"],"format":"double"},"sell_usd":{"type":["number","null"],"format":"double"},"total_buys":{"type":["integer","null"],"format":"int64"},"total_sells":{"type":["integer","null"],"format":"int64"},"total_fees":{"type":["number","null"],"format":"double"},"first_trade_at":{"type":["integer","null"],"format":"int64"},"last_trade_at":{"type":["integer","null"],"format":"int64"}}},"MarketHoldersResponse":{"type":"object","description":"Response for market (condition_id) holders endpoint","required":["condition_id","total_holders","outcomes"],"properties":{"condition_id":{"type":"string","description":"Market condition ID"},"question":{"type":["string","null"],"description":"Market question/title"},"slug":{"type":["string","null"],"description":"Market slug"},"total_holders":{"type":"integer","format":"int64","description":"Total unique holders across all outcomes (from holder_stats)"},"outcomes":{"type":"array","items":{"$ref":"#/components/schemas/OutcomeHolders"},"description":"Holders grouped by outcome"}}},"MarketMetadata":{"type":"object","description":"Market metadata (enriched, cached version)","required":["condition_id","question","description","slug","neg_risk","tokens","tags","outcomes","metrics","clob_rewards"],"properties":{"condition_id":{"type":"string"},"question":{"type":"string"},"description":{"type":"string"},"slug":{"type":"string"},"event_slug":{"type":["string","null"]},"event_id":{"type":["string","null"]},"event_title":{"type":["string","null"]},"series_slug":{"type":["string","null"]},"neg_risk":{"type":"boolean"},"tokens":{"type":"array","items":{"$ref":"#/components/schemas/TokenOutcome"}},"image_url":{"type":["string","null"]},"tags":{"type":"array","items":{"type":"string"}},"created_time":{"type":["integer","null"],"format":"int64"},"start_time":{"type":["integer","null"],"format":"int64"},"game_start_time":{"type":["integer","null"],"format":"int64"},"closed_time":{"type":["integer","null"],"format":"int64"},"end_time":{"type":["integer","null"],"format":"int64"},"title":{"type":["string","null"]},"id":{"type":["string","null"]},"volume_usd":{"type":["number","null"],"format":"double"},"liquidity_usd":{"type":["number","null"],"format":"double"},"outcomes":{"type":"array","items":{"$ref":"#/components/schemas/MarketOutcome"}},"metrics":{"type":"object","additionalProperties":{"type":"number","format":"double"},"propertyNames":{"type":"string"}},"market_maker_address":{"type":["string","null"]},"creator":{"type":["string","null"]},"category":{"type":["string","null"]},"clob_rewards":{"type":"array","items":{"$ref":"#/components/schemas/ClobReward"}}}},"MarketMetadataOutcome":{"type":"object","description":"Market outcome with timeframe metrics (websocket API format)","required":["token_id","outcome"],"properties":{"token_id":{"type":"string"},"outcome":{"type":"string"},"last_price":{"type":["number","null"],"format":"double"},"last_probability":{"type":["number","null"],"format":"double"},"metrics":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/OutcomeTimeframeMetrics"},"propertyNames":{"type":"string"}}}},"MarketOutcome":{"type":"object","description":"Outcome for market API responses","properties":{"name":{"type":"string","default":""},"price":{"type":["number","null"],"format":"double","default":null},"position_id":{"type":["string","null"],"default":null},"outcome_index":{"type":["integer","null"],"format":"int32","default":null}}},"MarketPnlSortBy":{"type":"string","enum":["realized_pnl_usd","buy_usd","total_buys","total_fees","outcomes_traded","realized_pnl_pct"]},"MarketResponse":{"type":"object","description":"Formatted market response with structured metrics, tags, outcomes, and event","required":["condition_id","status"],"properties":{"condition_id":{"type":"string"},"id":{"type":["string","null"]},"market_slug":{"type":["string","null"]},"question":{"type":["string","null"]},"title":{"type":["string","null"]},"description":{"type":["string","null"]},"image_url":{"type":["string","null"]},"oracle":{"type":["string","null"]},"status":{"type":"string"},"created_time":{"type":["integer","null"],"format":"int64"},"start_time":{"type":["integer","null"],"format":"int64"},"game_start_time":{"type":["integer","null"],"format":"int64"},"closed_time":{"type":["integer","null"],"format":"int64"},"end_time":{"type":["integer","null"],"format":"int64"},"accepting_orders":{"type":["boolean","null"]},"uma_resolution_status":{"type":["string","null"]},"is_neg_risk":{"type":["boolean","null"]},"market_maker_address":{"type":["string","null"]},"creator":{"type":["string","null"]},"category":{"type":["string","null"]},"volume_usd":{"type":["number","null"],"format":"double"},"liquidity_usd":{"type":["number","null"],"format":"double"},"highest_probability":{"type":["number","null"],"format":"double"},"total_holders":{"type":["integer","null"],"format":"int64"},"winning_outcome":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/MarketOutcome"}]},"outcomes":{"type":"array","items":{"$ref":"#/components/schemas/MarketOutcome"}},"rewards":{"type":"array","items":{"$ref":"#/components/schemas/MarketReward"}},"clob_rewards":{"type":"array","items":{"$ref":"#/components/schemas/ClobReward"}},"tags":{"type":"array","items":{"type":"string"}},"event_slug":{"type":["string","null"]},"resolution_source":{"type":["string","null"]},"metrics":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/SimpleTimeframeMetrics"},"propertyNames":{"type":"string"}},"relevance_score":{"type":["number","null"],"format":"double"}}},"MarketReward":{"type":"object","description":"Reward info for market API responses","properties":{"min_size":{"type":["number","null"],"format":"double","default":null},"max_spread":{"type":["number","null"],"format":"double","default":null},"daily_rate":{"type":["number","null"],"format":"double","default":null}}},"MarketSortBy":{"type":"string","enum":["volume","txns","unique_traders","liquidity","holders","end_time","start_time","created_time","relevance"]},"MarketStatus":{"type":"string","enum":["open","closed","all"]},"MarketVolumeChartResponse":{"type":"object","required":["volumes","has_more"],"properties":{"volumes":{"type":"array","items":{"$ref":"#/components/schemas/MarketVolumeDataPoint"}},"has_more":{"type":"boolean"}}},"MarketVolumeDataPoint":{"type":"object","required":["t","v","yv","nv","tc","ytc","ntc"],"properties":{"t":{"type":"integer","format":"int64"},"v":{"type":"number","format":"double"},"yv":{"type":"number","format":"double"},"nv":{"type":"number","format":"double"},"tc":{"type":"integer","format":"int32"},"ytc":{"type":"integer","format":"int32"},"ntc":{"type":"integer","format":"int32"}}},"MetricsTimeframe":{"type":"string","enum":["1m","5m","30m","1h","6h","24h","7d","30d"]},"OrderbookHistoryRow":{"type":"object","required":["ts","position_id","condition_id","bids","asks","hash"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"bids":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"asks":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"hash":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}},"OrderbookLevel":{"type":"object","description":"A single price level in a bids/asks array.","required":["p","s"],"properties":{"p":{"type":"string","description":"Price as a decimal string"},"s":{"type":"string","description":"Size as a decimal string"}}},"OrderbookSnapshotRow":{"type":"object","required":["ts","position_id","condition_id","bids","asks","hash"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"bids":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"asks":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"hash":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}},"OutcomeHolders":{"type":"object","description":"Holder data grouped by outcome for market-level queries","required":["outcome_index","outcome_name","position_id","total_holders","holders"],"properties":{"outcome_index":{"type":"integer","format":"int32","description":"Outcome index (0, 1, etc.)"},"outcome_name":{"type":"string","description":"Outcome name (Yes, No, etc.)"},"position_id":{"type":"string","description":"Position ID for this outcome"},"price":{"type":["number","null"],"format":"double","description":"Current price/probability"},"total_holders":{"type":"integer","format":"int64","description":"Total holders count from holder_stats"},"holders":{"type":"array","items":{"$ref":"#/components/schemas/Holder"},"description":"Top holders for this outcome"}}},"OutcomeIndex":{"type":"string","enum":["0","1"]},"OutcomeTimeframeMetrics":{"type":"object","properties":{"volume":{"type":"number","format":"double","default":0},"buy_volume":{"type":"number","format":"double","default":0},"sell_volume":{"type":"number","format":"double","default":0},"txns":{"type":"integer","format":"int32","default":0},"buys":{"type":"integer","format":"int32","default":0},"sells":{"type":"integer","format":"int32","default":0},"price_open":{"type":["number","null"],"format":"double","default":null},"price_close":{"type":["number","null"],"format":"double","default":null},"price_high":{"type":["number","null"],"format":"double","default":null},"price_low":{"type":["number","null"],"format":"double","default":null},"probability_open":{"type":["number","null"],"format":"double","default":null},"probability_close":{"type":["number","null"],"format":"double","default":null},"probability_high":{"type":["number","null"],"format":"double","default":null},"probability_low":{"type":["number","null"],"format":"double","default":null},"price_change_percent":{"type":["number","null"],"format":"double","default":null}}},"PaginationMeta":{"type":"object","description":"Pagination metadata to include in API responses","required":["has_more"],"properties":{"has_more":{"type":"boolean","description":"Whether there are more results available"},"pagination_key":{"type":["string","null"],"description":"Pagination key for the next page (if has_more is true)"}}},"PnlCandleEntry":{"type":"object","description":"A single PnL candle entry","required":["t","pnl"],"properties":{"t":{"type":"integer","format":"int64","description":"Timestamp in epoch seconds (start of bucket window)"},"pnl":{"type":"number","format":"double","description":"Realized PnL in this bucket (USD)"}}},"PnlCandleResolution":{"type":"string","enum":["1m","1h","1d"]},"PnlCandleTimeframe":{"type":"string","enum":["1d","7d","30d","lifetime"]},"PnlTimeframe":{"type":"string","enum":["1d","7d","30d","lifetime"]},"PolymarketEvent":{"type":"object","description":"A Polymarket event from the Gamma API","properties":{"id":{"type":"string","default":""},"event_slug":{"type":["string","null"],"default":null},"title":{"type":["string","null"],"default":null},"ticker":{"type":["string","null"],"default":null},"description":{"type":["string","null"],"default":null},"resolution_source":{"type":["string","null"],"default":null},"category":{"type":["string","null"],"default":null},"image_url":{"type":["string","null"],"default":null},"market_count":{"type":"integer","format":"int32","default":0},"created_time":{"type":["integer","null"],"format":"int64","default":null},"closed_time":{"type":["integer","null"],"format":"int64","default":null},"start_time":{"type":["integer","null"],"format":"int64","default":null},"end_time":{"type":["integer","null"],"format":"int64","default":null},"neg_risk":{"type":"boolean","default":false},"neg_risk_market_id":{"type":["string","null"],"default":null},"game_status":{"type":["string","null"],"default":null},"show_market_images":{"type":"boolean","default":false},"status":{"type":["string","null"],"description":"Event status: \"open\" or \"closed\"","default":null},"metrics":{"type":"object","default":{},"additionalProperties":{"$ref":"#/components/schemas/SimpleTimeframeMetrics"},"propertyNames":{"type":"string"}},"tags":{"type":"array","items":{"$ref":"#/components/schemas/PolymarketTag"},"default":[]},"markets":{"type":"array","items":{"$ref":"#/components/schemas/EventMarket"},"default":[]},"series":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PolymarketSeries"}],"default":null}}},"PolymarketSeries":{"type":"object","description":"A Polymarket series from the Gamma API\nSeries are parent groupings above events (e.g., \"NBA Season 2024-25\")","properties":{"id":{"type":"string","default":""},"slug":{"type":["string","null"],"default":null},"ticker":{"type":["string","null"],"default":null},"title":{"type":["string","null"],"default":null},"description":{"type":["string","null"],"default":null},"series_type":{"type":["string","null"],"default":null},"recurrence":{"type":["string","null"],"default":null},"layout":{"type":["string","null"],"default":null},"image_url":{"type":["string","null"],"default":null},"icon_url":{"type":["string","null"],"default":null},"active":{"type":"boolean","default":false},"closed":{"type":"boolean","default":false},"archived":{"type":"boolean","default":false},"featured":{"type":"boolean","default":false},"restricted":{"type":"boolean","default":false},"pyth_token_id":{"type":["string","null"],"default":null},"cg_asset_name":{"type":["string","null"],"default":null},"start_date":{"type":["integer","null"],"format":"int64","default":null},"event_count":{"type":"integer","format":"int32","default":0}}},"PolymarketTag":{"type":"object","description":"A Polymarket tag from the Gamma API","properties":{"id":{"type":"string","default":""},"label":{"type":"string","default":""},"slug":{"type":["string","null"],"default":null}}},"PolymarketUserProfile":{"type":"object","description":"Polymarket user profile (public API format)","required":["proxy_wallet","display_username_public","verified_badge","is_creator","is_mod"],"properties":{"proxy_wallet":{"type":"string"},"name":{"type":["string","null"]},"pseudonym":{"type":["string","null"]},"bio":{"type":["string","null"]},"profile_image":{"type":["string","null"]},"x_username":{"type":["string","null"]},"display_username_public":{"type":"boolean"},"verified_badge":{"type":"boolean"},"user_id":{"type":["string","null"]},"is_creator":{"type":"boolean"},"is_mod":{"type":"boolean"},"created_at":{"type":["string","null"]}}},"PositionChartDataPoint":{"type":"object","required":["v","t"],"properties":{"v":{"type":"number","format":"double"},"t":{"type":"integer","format":"int64","minimum":0}}},"PositionChartOutcome":{"type":"object","required":["position_id","name","outcome_index","data"],"properties":{"position_id":{"type":"string"},"name":{"type":"string"},"outcome_index":{"type":"integer","format":"int32"},"data":{"type":"array","items":{"$ref":"#/components/schemas/PositionChartDataPoint"}}}},"PositionHoldersResponse":{"type":"object","description":"Response for position (position_id) holders endpoint","required":["position_id","total_holders","holders"],"properties":{"position_id":{"type":"string","description":"Position ID (ERC1155 token ID)"},"condition_id":{"type":["string","null"],"description":"Condition ID this position belongs to"},"outcome_name":{"type":["string","null"],"description":"Outcome name"},"outcome_index":{"type":["integer","null"],"format":"int32","description":"Outcome index"},"price":{"type":["number","null"],"format":"double","description":"Current price"},"total_holders":{"type":"integer","format":"int64","description":"Total holders count from holder_stats"},"holders":{"type":"array","items":{"$ref":"#/components/schemas/Holder"},"description":"Top holders"}}},"PositionMetricsResponse":{"type":"object","description":"Response type for position metrics query","required":["position_id","condition_id","timeframe","volume_usd","buy_volume_usd","sell_volume_usd","fees","txns","buys","sells","unique_traders","price_open","price_high","price_low","price_close"],"properties":{"position_id":{"type":"string"},"condition_id":{"type":"string"},"timeframe":{"type":"string"},"volume_usd":{"type":"number","format":"double"},"buy_volume_usd":{"type":"number","format":"double"},"sell_volume_usd":{"type":"number","format":"double"},"fees":{"type":"number","format":"double"},"txns":{"type":"integer","format":"int32"},"buys":{"type":"integer","format":"int32"},"sells":{"type":"integer","format":"int32"},"unique_traders":{"type":"integer","format":"int32"},"price_open":{"type":"number","format":"double"},"price_high":{"type":"number","format":"double"},"price_low":{"type":"number","format":"double"},"price_close":{"type":"number","format":"double"}}},"PositionPnlSortBy":{"type":"string","enum":["realized_pnl_usd","buy_usd","sell_usd","redemption_usd","total_buys","total_sells","total_shares_bought","total_shares_sold","avg_entry_price","avg_exit_price","total_fees","first_trade_at","last_trade_at","current_value","realized_pnl_pct","title"]},"PositionVolumeChartResponse":{"type":"object","required":["volumes","has_more"],"properties":{"volumes":{"type":"array","items":{"$ref":"#/components/schemas/PositionVolumeDataPoint"}},"has_more":{"type":"boolean"}}},"PositionVolumeDataPoint":{"type":"object","required":["t","v","bv","sv","tc","btc","stc"],"properties":{"t":{"type":"integer","format":"int64"},"v":{"type":"number","format":"double"},"bv":{"type":"number","format":"double"},"sv":{"type":"number","format":"double"},"tc":{"type":"integer","format":"int32"},"btc":{"type":"integer","format":"int32"},"stc":{"type":"integer","format":"int32"}}},"PredictionCandlestickBar":{"type":"object","required":["t"],"properties":{"l":{"type":["number","null"],"format":"double"},"h":{"type":["number","null"],"format":"double"},"o":{"type":["number","null"],"format":"double"},"c":{"type":["number","null"],"format":"double"},"v":{"type":["number","null"],"format":"double"},"t":{"type":"integer","format":"int64","minimum":0},"tc":{"type":["integer","null"],"format":"int32"},"m":{"type":["number","null"],"format":"double"}}},"PredictionTradeResponse":{"type":"object","description":"Response format for prediction trades","required":["id","hash","block","confirmed_at","trader","taker","usd_amount","shares_amount","price","fee","exchange","trade_type","log_index","order_hash","position_id"],"properties":{"id":{"type":"string"},"hash":{"type":"string"},"block":{"type":"integer","format":"int64","minimum":0},"confirmed_at":{"type":"integer","format":"int64","minimum":0},"trader":{"$ref":"#/components/schemas/TraderInfo"},"taker":{"type":"string"},"side":{"type":["string","null"]},"condition_id":{"type":["string","null"]},"outcome":{"type":["string","null"]},"outcome_index":{"type":["integer","null"],"format":"int32"},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"slug":{"type":["string","null"]},"usd_amount":{"type":"number","format":"double"},"shares_amount":{"type":"number","format":"double"},"price":{"type":"number","format":"double"},"probability":{"type":["number","null"],"format":"double"},"fee":{"type":"number","format":"double"},"exchange":{"type":"string"},"trade_type":{"type":"string"},"log_index":{"type":"integer","format":"int64","minimum":0},"order_hash":{"type":"string"},"position_id":{"type":"string"}}},"PriceJump":{"type":"object","required":["from","to","price_before","price_after","change_pct","direction","volume","trades_count","condition_id"],"properties":{"from":{"type":"integer","format":"int64","minimum":0},"to":{"type":"integer","format":"int64","minimum":0},"price_before":{"type":"number","format":"double"},"price_after":{"type":"number","format":"double"},"change_pct":{"type":"number","format":"double"},"direction":{"type":"string"},"volume":{"type":"number","format":"double"},"trades_count":{"type":"integer","format":"int32"},"condition_id":{"type":"string"}}},"SearchResponse":{"type":"object","properties":{"events":{"type":["array","null"],"items":{"$ref":"#/components/schemas/PolymarketEvent"}},"events_pagination":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PaginationMeta"}]},"markets":{"type":["array","null"],"items":{"$ref":"#/components/schemas/MarketResponse"}},"markets_pagination":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PaginationMeta"}]},"traders":{"type":["array","null"],"items":{"$ref":"#/components/schemas/TraderWithPnl"}},"traders_pagination":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PaginationMeta"}]}}},"SearchSortBy":{"type":"string","description":"Combined sort options valid for both events and markets in search","enum":["volume","txns","unique_traders","relevance","title","creation_date","start_date","end_date","liquidity","holders","end_time","start_time","created_time"]},"SimpleTimeframeMetrics":{"type":"object","properties":{"volume":{"type":"number","format":"double","default":0},"fees":{"type":"number","format":"double","default":0},"txns":{"type":"integer","format":"int32","default":0},"unique_traders":{"type":"integer","format":"int32","default":0}}},"SortDirection":{"type":"string","enum":["asc","desc"]},"SpikeDirection":{"type":"string","description":"Direction filter for spike webhooks.","enum":["up","down","both"]},"SpreadRow":{"type":"object","description":"Lightweight row — derived metrics only, no bids/asks JSONB.","required":["ts","position_id","condition_id"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}},"TokenOutcome":{"type":"object","description":"Token outcome (position)","required":["token_id","outcome"],"properties":{"token_id":{"type":"string"},"outcome":{"type":"string"}}},"TradeSide":{"type":"string","enum":["0","1"]},"TradeType":{"type":"string","enum":["0","1","2","4","6"]},"Trader":{"type":"object","description":"Trader profile info embedded in API responses\n\nCorresponds to SQL function: `pm_build_trader(address, name, pseudonym, profile_image, x_username, verified_badge)`\n\nUsed in:\n- holders endpoints (market/event holders)\n- trades endpoints\n- leaderboard endpoints","required":["address"],"properties":{"address":{"type":"string"},"name":{"type":["string","null"]},"pseudonym":{"type":["string","null"]},"profile_image":{"type":["string","null"]},"x_username":{"type":["string","null"]},"verified_badge":{"type":"boolean"}}},"TraderEventPnlEntry":{"type":"object","description":"Event-level PnL entry","properties":{"event_slug":{"type":["string","null"]},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"markets_traded":{"type":["integer","null"],"format":"int64"},"outcomes_traded":{"type":["integer","null"],"format":"int64"},"total_buys":{"type":["integer","null"],"format":"int64"},"total_sells":{"type":["integer","null"],"format":"int64"},"total_redemptions":{"type":["integer","null"],"format":"int64"},"total_merges":{"type":["integer","null"],"format":"int64"},"total_volume_usd":{"type":["number","null"],"format":"double"},"buy_usd":{"type":["number","null"],"format":"double"},"sell_usd":{"type":["number","null"],"format":"double"},"redemption_usd":{"type":["number","null"],"format":"double"},"merge_usd":{"type":["number","null"],"format":"double"},"realized_pnl_usd":{"type":["number","null"],"format":"double"},"winning_markets":{"type":["integer","null"],"format":"int64"},"losing_markets":{"type":["integer","null"],"format":"int64"},"total_fees":{"type":["number","null"],"format":"double"},"first_trade_at":{"type":["integer","null"],"format":"int64"},"last_trade_at":{"type":["integer","null"],"format":"int64"}}},"TraderInfo":{"type":"object","description":"Trader profile info - backwards compatibility","required":["address"],"properties":{"address":{"type":"string"},"name":{"type":["string","null"]},"pseudonym":{"type":["string","null"]},"profile_image":{"type":["string","null"]},"x_username":{"type":["string","null"]},"verified_badge":{"type":"boolean"}}},"TraderMarketPnlEntry":{"type":"object","description":"Market-level PnL entry","properties":{"condition_id":{"type":["string","null"]},"event_slug":{"type":["string","null"]},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"outcomes_traded":{"type":["integer","null"],"format":"int64"},"total_buys":{"type":["integer","null"],"format":"int64"},"total_sells":{"type":["integer","null"],"format":"int64"},"total_redemptions":{"type":["integer","null"],"format":"int64"},"total_merges":{"type":["integer","null"],"format":"int64"},"buy_usd":{"type":["number","null"],"format":"double"},"sell_usd":{"type":["number","null"],"format":"double"},"redemption_usd":{"type":["number","null"],"format":"double"},"merge_usd":{"type":["number","null"],"format":"double"},"realized_pnl_usd":{"type":["number","null"],"format":"double"},"winning_outcomes":{"type":["integer","null"],"format":"int64"},"total_fees":{"type":["number","null"],"format":"double"},"first_trade_at":{"type":["integer","null"],"format":"int64"},"last_trade_at":{"type":["integer","null"],"format":"int64"}}},"TraderOutcomePnlEntry":{"type":"object","description":"Outcome-level PnL entry (per outcome token / position_id)","properties":{"position_id":{"type":["string","null"]},"condition_id":{"type":["string","null"]},"market_slug":{"type":["string","null"]},"event_slug":{"type":["string","null"]},"title":{"type":["string","null"]},"image_url":{"type":["string","null"]},"outcome":{"type":["string","null"]},"outcome_index":{"type":["integer","null"],"format":"int32"},"won":{"type":["boolean","null"],"description":"TRUE = won, FALSE = lost, NULL = open or sold before resolution"},"total_buys":{"type":["integer","null"],"format":"int64"},"total_sells":{"type":["integer","null"],"format":"int64"},"total_shares_bought":{"type":["number","null"],"format":"double"},"total_shares_sold":{"type":["number","null"],"format":"double"},"total_buy_usd":{"type":["number","null"],"format":"double"},"total_sell_usd":{"type":["number","null"],"format":"double"},"redemption_usd":{"type":["number","null"],"format":"double","description":"Payout on redemption (non-zero only if won)"},"avg_entry_price":{"type":["number","null"],"format":"double","description":"VWAP price paid per share across all buys (0–1)"},"avg_exit_price":{"type":["number","null"],"format":"double","description":"VWAP price received per share across all sells (0–1)"},"realized_pnl_usd":{"type":["number","null"],"format":"double"},"total_fees":{"type":["number","null"],"format":"double"},"first_trade_at":{"type":["integer","null"],"format":"int64"},"last_trade_at":{"type":["integer","null"],"format":"int64"},"current_price":{"type":["number","null"],"format":"double","description":"Last traded price for this outcome (0–1). NULL if market_outcomes has no price yet."},"current_shares_balance":{"type":["number","null"],"format":"double","description":"Current shares held: balance / 1e6."},"current_value":{"type":["number","null"],"format":"double","description":"Estimated current USD value of held shares: (balance / 1e6) * current_price.\nOnly meaningful for open positions (balance > 0)."},"realized_pnl_pct":{"type":["number","null"],"format":"double","description":"Realized PnL as a percentage of total spend: (realized_pnl_usd / total_buy_usd) * 100.\nNULL when total_buy_usd = 0."}}},"TraderPnlSummary":{"type":"object","description":"Trader's global PnL summary (single trader)","properties":{"trader":{"type":["string","null"]},"realized_pnl_usd":{"type":["number","null"],"format":"double"},"events_traded":{"type":["integer","null"],"format":"int64"},"markets_traded":{"type":["integer","null"],"format":"int64"},"total_buys":{"type":["integer","null"],"format":"int64"},"total_sells":{"type":["integer","null"],"format":"int64"},"total_redemptions":{"type":["integer","null"],"format":"int64"},"total_merges":{"type":["integer","null"],"format":"int64"},"total_volume_usd":{"type":["number","null"],"format":"double"},"buy_volume_usd":{"type":["number","null"],"format":"double"},"sell_volume_usd":{"type":["number","null"],"format":"double"},"redemption_volume_usd":{"type":["number","null"],"format":"double"},"merge_volume_usd":{"type":["number","null"],"format":"double"},"markets_won":{"type":["integer","null"],"format":"int64"},"markets_lost":{"type":["integer","null"],"format":"int64"},"market_win_rate_pct":{"type":["number","null"],"format":"double"},"avg_pnl_per_market":{"type":["number","null"],"format":"double"},"avg_pnl_per_trade":{"type":["number","null"],"format":"double"},"avg_hold_time_seconds":{"type":["number","null"],"format":"double"},"total_fees":{"type":["number","null"],"format":"double"},"best_trade_pnl_usd":{"type":["number","null"],"format":"double"},"best_trade_condition_id":{"type":["string","null"]},"first_trade_at":{"type":["integer","null"],"format":"int64"},"last_trade_at":{"type":["integer","null"],"format":"int64"}}},"TraderVolumeChartResponse":{"type":"object","required":["volumes","has_more"],"properties":{"volumes":{"type":"array","items":{"$ref":"#/components/schemas/TraderVolumeDataPoint"}},"has_more":{"type":"boolean"}}},"TraderVolumeDataPoint":{"type":"object","required":["t","v","bv","sv","tc","btc","stc"],"properties":{"t":{"type":"integer","format":"int64"},"v":{"type":"number","format":"double"},"bv":{"type":"number","format":"double"},"sv":{"type":"number","format":"double"},"tc":{"type":"integer","format":"int32"},"btc":{"type":"integer","format":"int32"},"stc":{"type":"integer","format":"int32"}}},"TraderWithPnl":{"allOf":[{"$ref":"#/components/schemas/Trader"},{"type":"object","properties":{"pnl":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/TraderPnlSummary"}]}}}]},"WebhookAssetSymbol":{"type":"string","description":"Crypto asset symbols accepted by `asset_price_tick` and `asset_price_window_update` filters.","enum":["BTC","ETH","SOL","XRP","DOGE","BNB","HYPE"]},"WebhookTimeframe":{"type":"string","description":"Timeframe values accepted by webhook metric, milestone, spike, and asset-price filters.","enum":["1m","5m","15m","30m","1h","4h","6h","1d","24h","7d","30d"]}}}} \ No newline at end of file +{"openapi":"3.1.0","info":{"title":"Polymarket API","description":"RESTful API for querying Polymarket prediction markets data including events, markets, traders, holders, and real-time metrics","license":{"name":""},"version":"1.0.0"},"servers":[{"url":"https://api.struct.to/v1","description":"Production"}],"paths":{"/polymarket/asset-history":{"get":{"tags":["Assets"],"summary":"Get Asset Price History","description":"Returns historical price data for supported crypto assets from Polymarket API","operationId":"get_asset_history","parameters":[{"name":"asset_symbol","in":"query","description":"Asset ticker: BTC, ETH, XRP, SOL, DOGE, BNB, HYPE","required":true,"schema":{"type":"string"},"example":"BTC"},{"name":"variant","in":"query","description":"Time window: 5m, 15m, 1h, 4h, 1d","required":true,"schema":{"type":"string"},"example":"1h"},{"name":"from","in":"query","description":"Start timestamp in seconds (Unix epoch, inclusive)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp in seconds (Unix epoch, inclusive)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"limit","in":"query","description":"Number of results (default: 10, max: 100)","required":false,"schema":{"type":"integer","format":"int64"},"example":10}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AssetPriceHistoryRow"}}}}},"400":{"description":"Bad request - missing or invalid parameters"},"500":{"description":"Internal server error"}}}},"/polymarket/events":{"get":{"tags":["Events"],"summary":"Get events","description":"Retrieve a paginated list of events with filtering, sorting, and optional nested tags/markets","operationId":"get_events","parameters":[{"name":"id","in":"query","description":"Filter by event ID(s) - comma-separated (max 50). Cannot be used with 'event_slugs'. Example: id=99600,99601,99583","required":false,"schema":{"type":"string"}},{"name":"event_slugs","in":"query","description":"Filter by event slug(s) - comma-separated (max 50). Cannot be used with 'id'. Example: event_slugs=will-trump-win,bitcoin-100k","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","description":"Search in title and description (3-100 characters). Example: search=trump","required":false,"schema":{"type":"string"}},{"name":"sort_by","in":"query","description":"Sort: volume, txns, unique_traders, title, creation_date, start_date, end_date, relevance (relevance only works in search mode) (default: volume)","required":false,"schema":{"$ref":"#/components/schemas/EventSortBy"}},{"name":"sort_dir","in":"query","description":"Sort direction: asc, desc (default: desc)","required":false,"schema":{"$ref":"#/components/schemas/SortDirection"}},{"name":"timeframe","in":"query","description":"Metrics timeframe: 1m, 5m, 30m, 1h, 6h, 24h, 7d, 30d (default: 24h)","required":false,"schema":{"$ref":"#/components/schemas/MetricsTimeframe"}},{"name":"status","in":"query","description":"Filter by status: open, closed, or all (default: all)","required":false,"schema":{"$ref":"#/components/schemas/MarketStatus"}},{"name":"categories","in":"query","description":"Comma-separated category filters","required":false,"schema":{"type":"string"}},{"name":"exclude_categories","in":"query","description":"Comma-separated categories to exclude","required":false,"schema":{"type":"string"}},{"name":"tags","in":"query","description":"Filter by tag slug(s) - comma-separated (max 50). Example: tags=sports,football,crypto","required":false,"schema":{"type":"string"}},{"name":"exclude_tags","in":"query","description":"Comma-separated tag slugs to exclude","required":false,"schema":{"type":"string"}},{"name":"min_volume","in":"query","description":"Minimum volume in selected timeframe","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_volume","in":"query","description":"Maximum volume in selected timeframe","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_txns","in":"query","description":"Minimum transactions in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"max_txns","in":"query","description":"Maximum transactions in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"min_unique_traders","in":"query","description":"Minimum unique traders in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"max_unique_traders","in":"query","description":"Maximum unique traders in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"include_tags","in":"query","description":"Include tags array (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_markets","in":"query","description":"Include markets array with outcomes (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_metrics","in":"query","description":"Include metrics object with all timeframes (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key","required":false,"schema":{"type":"string"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of Polymarket events with nested tags, markets, and series. Response includes `pagination: { has_more, pagination_key }` for cursor-based pagination.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PolymarketEvent"}}}}},"400":{"description":"Bad request - validation error (search length, array limits, conflicting params)"}}}},"/polymarket/events/chart":{"get":{"tags":["Events"],"summary":"Get event chart","description":"Retrieve price data over time for up to 4 markets with highest YES outcome (outcome_index 0) prices in an event. Perfect for rendering multi-line charts showing price movement across top markets. TradingView-style: resolution parameter determines both candle size and implicit lookback period.","operationId":"get_event_chart","parameters":[{"name":"event_slug","in":"query","description":"Event slug (required)","required":true,"schema":{"type":"string"}},{"name":"condition_ids","in":"query","description":"Comma-separated condition IDs to include (max 4, optional)","required":false,"schema":{"type":"string"}},{"name":"market_slugs","in":"query","description":"Comma-separated market slugs to include (max 4, optional). Use either condition_ids or market_slugs, not both","required":false,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Time interval with implicit lookback: 1H (1 hour), 6H (6 hours), 1D (1 day), 1W (1 week), 1M (30 days), ALL (all data) (required)","required":true,"schema":{"type":"string","enum":["1H","6H","1D","1W","1M","ALL"]}}],"responses":{"200":{"description":"Price data over time for up to 4 markets with highest YES odds","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventMarketChartOutcome"}}}}}}}},"/polymarket/events/metrics":{"get":{"tags":["Events"],"summary":"Get event metrics","description":"Retrieve volume, transaction, and trader metrics for an event. Supports single timeframe (e.g., '1m'), multiple timeframes (e.g., '1m,5m,1h'), or 'all' to get all available timeframes.","operationId":"get_event_metrics","parameters":[{"name":"event_slug","in":"query","description":"Event slug","required":true,"schema":{"type":"string"}},{"name":"timeframe","in":"query","description":"Timeframe: single (1m, 5m, 30m, 1h, 6h, 24h, 7d, 30d), comma-separated (1m,5m,1h), or 'all'","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Event metrics for the specified timeframe(s). Returns single object for one timeframe, array for multiple.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventMetricsResponse"}}}},"400":{"description":"Invalid timeframe"}}}},"/polymarket/events/outcomes":{"get":{"tags":["Events"],"summary":"Get event market outcomes","description":"Returns the winning outcome name for each resolved market in an event, keyed by market slug. Useful for quickly checking which outcomes won across a series.","operationId":"get_event_outcomes","parameters":[{"name":"event_slug","in":"query","description":"Event slug (required)","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Number of resolved markets per page (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key for fetching next page","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Map of market_slug → winning outcome name with pagination metadata","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}}}}},"400":{"description":"Missing event_slug parameter"}}}},"/polymarket/events/slug/{event_slug}":{"get":{"tags":["Events"],"summary":"Get event by slug","description":"Retrieve a single event by its slug with optional nested tags, markets, and metrics","operationId":"get_event_by_slug","parameters":[{"name":"event_slug","in":"path","description":"Event slug","required":true,"schema":{"type":"string"}},{"name":"include_tags","in":"query","description":"Include tags array (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_markets","in":"query","description":"Include markets array with outcomes (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_metrics","in":"query","description":"Include metrics object with all timeframes (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Event with nested tags, markets, and series","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PolymarketEvent"}}}},"404":{"description":"Event not found"}}}},"/polymarket/events/{identifier}":{"get":{"tags":["Events"],"summary":"Get event by ID or slug","description":"Retrieve a single event by its numeric ID or slug with optional nested tags, markets, and metrics","operationId":"get_event","parameters":[{"name":"identifier","in":"path","description":"Event ID or slug","required":true,"schema":{"type":"string"}},{"name":"include_tags","in":"query","description":"Include tags array (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_markets","in":"query","description":"Include markets array with outcomes (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_metrics","in":"query","description":"Include metrics object with all timeframes (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Event with nested tags, markets, and series","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PolymarketEvent"}}}},"404":{"description":"Event not found"}}}},"/polymarket/holders/markets":{"get":{"tags":["Holders"],"summary":"Get market holders","description":"Retrieve holders of a market grouped by outcome, sorted by shares held. Identify the market with either `condition_id` or `market_slug` — exactly one must be provided. Set `include_pnl=true` to include a nested holder `pnl` object.","operationId":"get_market_holders","parameters":[{"name":"condition_id","in":"query","description":"Market condition ID (0x-prefixed hex)","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (e.g. `will-trump-win`)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"min_shares","in":"query","description":"Minimum shares held (decimal string)","required":false,"schema":{"type":"string"}},{"name":"max_shares","in":"query","description":"Maximum shares held (decimal string)","required":false,"schema":{"type":"string"}},{"name":"include_pnl","in":"query","description":"Include nested holder PnL data (default: false, +1 credit)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Market holders grouped by outcome (sorted by shares DESC). Holder `pnl` is included only when `include_pnl=true`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarketHoldersResponse"}}}},"404":{"description":"Market not found"}}}},"/polymarket/holders/markets/history":{"get":{"tags":["Holders"],"summary":"Get market holders history","description":"Retrieve historical holder count snapshots for a market over a time range. Identify the market with either `condition_id` or `market_slug` — exactly one must be provided.","operationId":"get_market_holders_history","parameters":[{"name":"condition_id","in":"query","description":"Market condition ID (0x-prefixed hex)","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (e.g. `will-trump-win`)","required":false,"schema":{"type":"string"}},{"name":"hours","in":"query","description":"Time range in hours (default: 24, max: 336 = 14 days)","required":false,"schema":{"type":"number","format":"double"}}],"responses":{"200":{"description":"Market holder count history with automatic granularity (1m/5m/15m/1h/6h buckets)","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/HolderHistoryCandle"}}}}},"404":{"description":"Market not found"}}}},"/polymarket/holders/positions/{position_id}":{"get":{"tags":["Holders"],"summary":"Get position holders","description":"Retrieve holders of a specific position (ERC1155 token), sorted by shares held. Set `include_pnl=true` to include nested holder PnL. Uses cursor-based pagination for efficient traversal.","operationId":"get_position_holders","parameters":[{"name":"position_id","in":"path","description":"Position ID (ERC1155 token ID)","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key","required":false,"schema":{"type":"string"}},{"name":"min_shares","in":"query","description":"Minimum shares held (decimal string)","required":false,"schema":{"type":"string"}},{"name":"max_shares","in":"query","description":"Maximum shares held (decimal string)","required":false,"schema":{"type":"string"}},{"name":"include_pnl","in":"query","description":"Include nested holder PnL data (default: false, +1 credit)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Position holders (sorted by shares DESC). Holder `pnl` is included only when `include_pnl=true`. Response includes `pagination: { has_more, pagination_key }` for cursor-based pagination.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PositionHoldersResponse"}}}},"404":{"description":"Position not found"}}}},"/polymarket/holders/positions/{position_id}/history":{"get":{"tags":["Holders"],"summary":"Get position holders history","description":"Retrieve historical holder count snapshots for a position over a time range","operationId":"get_position_holders_history","parameters":[{"name":"position_id","in":"path","description":"Position ID (ERC1155 token ID)","required":true,"schema":{"type":"string"}},{"name":"hours","in":"query","description":"Time range in hours (default: 24, max: 336 = 14 days)","required":false,"schema":{"type":"number","format":"double"}}],"responses":{"200":{"description":"Position holder count history with automatic granularity (1m/5m/15m/1h/6h buckets)","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/HolderHistoryCandle"}}}}},"404":{"description":"Position not found"}}}},"/polymarket/market":{"get":{"tags":["Market"],"summary":"Get markets","description":"Retrieve a paginated list of markets with filtering, sorting, and optional nested tags/events/metrics","operationId":"list_markets","parameters":[{"name":"condition_ids","in":"query","description":"Filter by condition ID(s) - comma-separated (max 50)","required":false,"schema":{"type":"string"}},{"name":"question_ids","in":"query","description":"Filter by question ID(s) - comma-separated (max 50)","required":false,"schema":{"type":"string"}},{"name":"market_ids","in":"query","description":"Filter by market ID(s) - comma-separated (max 50)","required":false,"schema":{"type":"string"}},{"name":"market_slugs","in":"query","description":"Filter by market slug(s) - comma-separated (max 50)","required":false,"schema":{"type":"string"}},{"name":"event_slugs","in":"query","description":"Filter by event slug(s) - comma-separated (max 50)","required":false,"schema":{"type":"string"}},{"name":"position_ids","in":"query","description":"Filter by position ID(s) - comma-separated (max 50)","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","description":"Search in title (3-100 characters)","required":false,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Filter by status: open, closed, or all (default: all)","required":false,"schema":{"$ref":"#/components/schemas/MarketStatus"}},{"name":"sort_by","in":"query","description":"Sort: volume, txns, unique_traders, liquidity, holders, end_time, start_time, created_time, relevance","required":false,"schema":{"$ref":"#/components/schemas/MarketSortBy"}},{"name":"sort_dir","in":"query","description":"Sort direction: asc, desc (default: desc)","required":false,"schema":{"$ref":"#/components/schemas/SortDirection"}},{"name":"timeframe","in":"query","description":"Metrics timeframe: 1m, 5m, 30m, 1h, 6h, 24h, 7d, 30d (default: 24h)","required":false,"schema":{"$ref":"#/components/schemas/MetricsTimeframe"}},{"name":"min_volume","in":"query","description":"Minimum total volume USD","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_volume","in":"query","description":"Maximum total volume USD","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_liquidity","in":"query","description":"Minimum liquidity USD","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_liquidity","in":"query","description":"Maximum liquidity USD","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_txns","in":"query","description":"Minimum transactions in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"max_txns","in":"query","description":"Maximum transactions in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"min_unique_traders","in":"query","description":"Minimum unique traders in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"max_unique_traders","in":"query","description":"Maximum unique traders in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"min_holders","in":"query","description":"Minimum total holders","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"max_holders","in":"query","description":"Maximum total holders","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"categories","in":"query","description":"Comma-separated category filters (max 50)","required":false,"schema":{"type":"string"}},{"name":"exclude_categories","in":"query","description":"Comma-separated categories to exclude","required":false,"schema":{"type":"string"}},{"name":"tags","in":"query","description":"Filter by tag(s) - comma-separated (max 50)","required":false,"schema":{"type":"string"}},{"name":"exclude_tags","in":"query","description":"Comma-separated tags to exclude","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Filter markets with end_time >= start_time (Unix timestamp)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"end_time","in":"query","description":"Filter markets with end_time <= end_time (Unix timestamp)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"include_tags","in":"query","description":"Include tags array (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_event","in":"query","description":"Include event object (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_metrics","in":"query","description":"Include all timeframe metrics (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key","required":false,"schema":{"type":"string"}},{"name":"has_rewards","in":"query","description":"Only return markets that have CLOB rewards (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of markets with metadata, outcomes, tags, event, and metrics. Response includes `pagination: { has_more, pagination_key }` for cursor-based pagination.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MarketResponse"}}}}},"400":{"description":"Bad request - validation error (search length, array limits, conflicting params)"}}}},"/polymarket/market/bonds":{"get":{"tags":["Bonds"],"summary":"Get bonds","description":"Retrieve a list of bond markets sorted by yield, filtered by probability and time to expiry","operationId":"get_bonds","parameters":[{"name":"min_probability","in":"query","description":"Minimum probability threshold (default: 0.85)","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_hours","in":"query","description":"Maximum hours until market end","required":false,"schema":{"type":"number","format":"double"}},{"name":"limit","in":"query","description":"Number of results (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor for pagination: end_date (unix epoch) of the last item from the previous page","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"List of bond markets sorted by yield","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BondMarket"}}}}}}}},"/polymarket/market/candlestick":{"get":{"tags":["Market"],"summary":"Get market candlesticks by condition_id","description":"Retrieve OHLCV candlestick data for a market by its condition_id","operationId":"get_market_candlestick","parameters":[{"name":"condition_id","in":"query","description":"Market condition ID (required)","required":true,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Candle interval: 1, 5, 15, 30, 60, 240, D, 1D","required":true,"schema":{"$ref":"#/components/schemas/CandlestickResolution"}},{"name":"count_back","in":"query","description":"Number of candles (max: 2500)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"from","in":"query","description":"Start timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"OHLCV candlestick data","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PredictionCandlestickBar"}}}}}}}},"/polymarket/market/chart":{"get":{"tags":["Market"],"summary":"Get market chart","description":"Retrieve price data over time for up to 4 position outcomes in a market condition. TradingView-style: resolution parameter determines both candle size and implicit lookback period. Auto-selects the 4 most active outcomes if position_ids not specified.","operationId":"get_chart","parameters":[{"name":"condition_id","in":"query","description":"Market condition ID or market_slug (one required)","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (alternative to condition_id)","required":false,"schema":{"type":"string"}},{"name":"position_ids","in":"query","description":"Comma-separated list of position IDs (max 4, optional). Auto-selected if not provided","required":false,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Time interval with implicit lookback: 1H (1 hour), 6H (6 hours), 1D (1 day), 1W (1 week), 1M (30 days), ALL (all data) (required)","required":true,"schema":{"type":"string","enum":["1H","6H","1D","1W","1M","ALL"]}}],"responses":{"200":{"description":"Price data over time for up to 4 market outcomes","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PositionChartOutcome"}}}}}}}},"/polymarket/market/metrics":{"get":{"tags":["Market"],"summary":"Get market metrics","description":"Retrieve volume, transaction, and trader metrics for a market. Supports single timeframe (e.g., '1m'), multiple timeframes (e.g., '1m,5m,1h'), or 'all' to get all available timeframes.","operationId":"get_market_metrics","parameters":[{"name":"condition_id","in":"query","description":"Market condition ID","required":true,"schema":{"type":"string"}},{"name":"timeframe","in":"query","description":"Timeframe: single (1m, 5m, 30m, 1h, 6h, 24h, 7d, 30d), comma-separated (1m,5m,1h), or 'all'","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Market metrics for the specified timeframe(s). Returns single object for one timeframe, array for multiple.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConditionMetricsResponse"}}}},"400":{"description":"Invalid timeframe"}}}},"/polymarket/market/position/candlestick":{"get":{"tags":["Market"],"summary":"Get position candlesticks by position_id","description":"Retrieve OHLCV candlestick data for a specific position by its position_id","operationId":"get_position_candlestick","parameters":[{"name":"position_id","in":"query","description":"Position/token ID (required)","required":true,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Candle interval: 1, 5, 15, 30, 60, 240, D, 1D","required":true,"schema":{"$ref":"#/components/schemas/CandlestickResolution"}},{"name":"count_back","in":"query","description":"Number of candles (max: 2500)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"from","in":"query","description":"Start timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"OHLCV candlestick data","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PredictionCandlestickBar"}}}}}}}},"/polymarket/market/position/metrics":{"get":{"tags":["Market"],"summary":"Get position metrics","description":"Retrieve volume, transaction, and trader metrics for a specific position. Supports single timeframe (e.g., '1m'), multiple timeframes (e.g., '1m,5m,1h'), or 'all' to get all available timeframes.","operationId":"get_position_metrics","parameters":[{"name":"position_id","in":"query","description":"Position/token ID","required":true,"schema":{"type":"string"}},{"name":"timeframe","in":"query","description":"Timeframe: single (1m, 5m, 30m, 1h, 6h, 24h, 7d, 30d), comma-separated (1m,5m,1h), or 'all'","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Position metrics for the specified timeframe(s). Returns single object for one timeframe, array for multiple.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PositionMetricsResponse"}}}},"400":{"description":"Invalid timeframe"}}}},"/polymarket/market/position/volume-chart":{"get":{"tags":["Market"],"summary":"Get position volume chart","description":"Retrieve volume over time for a specific position with buy/sell breakdown","operationId":"get_position_volume_chart","parameters":[{"name":"position_id","in":"query","description":"Position/token ID (required)","required":true,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Time interval: 1, 5, 15, 30, 60, 240, D, 1D (default: 60)","required":false,"schema":{"$ref":"#/components/schemas/CandlestickResolution"}},{"name":"count_back","in":"query","description":"Number of data points (max: 2500)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"from","in":"query","description":"Start timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Volume with buy/sell breakdown over time","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PositionVolumeDataPoint"}}}}}}}},"/polymarket/market/price-jumps":{"get":{"tags":["Market"],"summary":"Detect price jumps","description":"Scan candles for significant price movements. Returns jumps with from/to timestamps in milliseconds, directly usable as trades API time range parameters to identify traders who traded before or during the movement.","operationId":"get_price_jumps","parameters":[{"name":"condition_id","in":"query","description":"Market condition ID (one of condition_id or market_slug required)","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (resolved to condition_id)","required":false,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Candle resolution in minutes: 1, 5, 15, 30, 60, 240 (default: 15)","required":false,"schema":{"type":"string"}},{"name":"min_change_pct","in":"query","description":"Minimum relative percent change to qualify as a jump (default: 10.0)","required":false,"schema":{"type":"number","format":"double"}},{"name":"lookback","in":"query","description":"Number of candles to scan back from now (default: 1440, max: 2500)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"offset","in":"query","description":"Offset in candles from now — window is [now - (lookback + offset) * resolution, now - offset * resolution] (default: 0)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Price jumps sorted by timestamp descending","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PriceJump"}}}}}}}},"/polymarket/market/slug/{market_slug}":{"get":{"tags":["Market"],"summary":"Get market by slug","description":"Retrieve a single market by its slug with optional nested tags, event, and metrics","operationId":"get_market_by_slug","parameters":[{"name":"market_slug","in":"path","description":"Market slug (e.g. `will-trump-win`)","required":true,"schema":{"type":"string"}},{"name":"include_tags","in":"query","description":"Include tags array (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_event","in":"query","description":"Include event object (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_metrics","in":"query","description":"Include all timeframe metrics (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Market with metadata, outcomes, tags, event, and metrics","content":{"application/json":{"schema":{"type":"object","description":"Formatted market response with structured metrics, tags, outcomes, and event","required":["condition_id","status"],"properties":{"condition_id":{"type":"string"},"id":{"type":["string","null"]},"market_slug":{"type":["string","null"]},"question":{"type":["string","null"]},"title":{"type":["string","null"]},"description":{"type":["string","null"]},"image_url":{"type":["string","null"]},"oracle":{"type":["string","null"]},"status":{"type":"string"},"created_time":{"type":["integer","null"],"format":"int64"},"start_time":{"type":["integer","null"],"format":"int64"},"game_start_time":{"type":["integer","null"],"format":"int64"},"closed_time":{"type":["integer","null"],"format":"int64"},"end_time":{"type":["integer","null"],"format":"int64"},"accepting_orders":{"type":["boolean","null"]},"uma_resolution_status":{"type":["string","null"]},"is_neg_risk":{"type":["boolean","null"]},"market_maker_address":{"type":["string","null"]},"creator":{"type":["string","null"]},"category":{"type":["string","null"]},"volume_usd":{"type":["number","null"],"format":"double"},"liquidity_usd":{"type":["number","null"],"format":"double"},"highest_probability":{"type":["number","null"],"format":"double"},"total_holders":{"type":["integer","null"],"format":"int64"},"winning_outcome":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/MarketOutcome"}]},"outcomes":{"type":"array","items":{"$ref":"#/components/schemas/MarketOutcome"}},"rewards":{"type":"array","items":{"$ref":"#/components/schemas/MarketReward"}},"clob_rewards":{"type":"array","items":{"$ref":"#/components/schemas/ClobReward"}},"tags":{"type":"array","items":{"type":"string"}},"event_slug":{"type":["string","null"]},"resolution_source":{"type":["string","null"]},"metrics":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/SimpleTimeframeMetrics"},"propertyNames":{"type":"string"}},"relevance_score":{"type":["number","null"],"format":"double"}}}}}},"404":{"description":"Market not found"}}}},"/polymarket/market/trades":{"get":{"tags":["Market"],"summary":"Get market trades","description":"Retrieve trades for one or more markets, with filtering by trader, side, price, amount, and time range","operationId":"get_market_trades","parameters":[{"name":"condition_ids","in":"query","description":"Comma-separated condition IDs (max 20)","required":false,"schema":{"type":"string"}},{"name":"slugs","in":"query","description":"Comma-separated market slugs","required":false,"schema":{"type":"string"}},{"name":"position_ids","in":"query","description":"Comma-separated position IDs","required":false,"schema":{"type":"string"}},{"name":"traders","in":"query","description":"Comma-separated trader addresses (max 25)","required":false,"schema":{"type":"string"}},{"name":"side","in":"query","description":"Trade side: 0 (Buy), 1 (Sell)","required":false,"schema":{"$ref":"#/components/schemas/TradeSide"}},{"name":"outcome","in":"query","description":"Outcome name filter (e.g. Yes, No)","required":false,"schema":{"type":"string"}},{"name":"outcome_index","in":"query","description":"Outcome index: 0 (Yes), 1 (No)","required":false,"schema":{"$ref":"#/components/schemas/OutcomeIndex"}},{"name":"trade_types","in":"query","description":"Comma-separated trade types: OrderFilled, Redemption, Merge, Split, Cancelled, PositionsConverted, OrdersMatched","required":false,"schema":{"type":"string"}},{"name":"min_usd_amount","in":"query","description":"Min USD amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_usd_amount","in":"query","description":"Max USD amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_shares_amount","in":"query","description":"Min shares amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_shares_amount","in":"query","description":"Max shares amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_price","in":"query","description":"Min price (0.0-1.0)","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_price","in":"query","description":"Max price (0.0-1.0)","required":false,"schema":{"type":"number","format":"double"}},{"name":"from","in":"query","description":"Start timestamp (ms)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (ms)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"all","in":"query","description":"Return all-time trades, not just last 30 days (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Results per page (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32","minimum":0}},{"name":"pagination_key","in":"query","description":"Offset-based pagination key (integer offset into result set)","required":false,"schema":{"type":"integer","format":"int32","minimum":0}},{"name":"sort_desc","in":"query","description":"Sort newest first (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Prediction trades matching filters","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PredictionTradeResponse"}}}}}}}},"/polymarket/market/volume-chart":{"get":{"tags":["Market"],"summary":"Get market volume chart","description":"Retrieve volume breakdown by YES/NO outcome over time for a prediction market","operationId":"get_market_volume_chart","parameters":[{"name":"condition_id","in":"query","description":"Market condition ID (or use market_slug)","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (alternative to condition_id)","required":false,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Time interval: 1, 5, 15, 30, 60, 240, D, 1D (default: 60)","required":false,"schema":{"$ref":"#/components/schemas/CandlestickResolution"}},{"name":"count_back","in":"query","description":"Number of data points (max: 2500)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"from","in":"query","description":"Start timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Volume breakdown by YES/NO over time","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MarketVolumeDataPoint"}}}}}}}},"/polymarket/market/{condition_id}":{"get":{"tags":["Market"],"summary":"Get market by condition ID","description":"Retrieve a single market by its condition ID with optional nested tags, event, and metrics","operationId":"get_market","parameters":[{"name":"condition_id","in":"path","description":"Market condition ID (0x-prefixed hex)","required":true,"schema":{"type":"string"}},{"name":"include_tags","in":"query","description":"Include tags array (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_event","in":"query","description":"Include event object (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_metrics","in":"query","description":"Include all timeframe metrics (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Market with metadata, outcomes, tags, event, and metrics","content":{"application/json":{"schema":{"type":"object","description":"Formatted market response with structured metrics, tags, outcomes, and event","required":["condition_id","status"],"properties":{"condition_id":{"type":"string"},"id":{"type":["string","null"]},"market_slug":{"type":["string","null"]},"question":{"type":["string","null"]},"title":{"type":["string","null"]},"description":{"type":["string","null"]},"image_url":{"type":["string","null"]},"oracle":{"type":["string","null"]},"status":{"type":"string"},"created_time":{"type":["integer","null"],"format":"int64"},"start_time":{"type":["integer","null"],"format":"int64"},"game_start_time":{"type":["integer","null"],"format":"int64"},"closed_time":{"type":["integer","null"],"format":"int64"},"end_time":{"type":["integer","null"],"format":"int64"},"accepting_orders":{"type":["boolean","null"]},"uma_resolution_status":{"type":["string","null"]},"is_neg_risk":{"type":["boolean","null"]},"market_maker_address":{"type":["string","null"]},"creator":{"type":["string","null"]},"category":{"type":["string","null"]},"volume_usd":{"type":["number","null"],"format":"double"},"liquidity_usd":{"type":["number","null"],"format":"double"},"highest_probability":{"type":["number","null"],"format":"double"},"total_holders":{"type":["integer","null"],"format":"int64"},"winning_outcome":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/MarketOutcome"}]},"outcomes":{"type":"array","items":{"$ref":"#/components/schemas/MarketOutcome"}},"rewards":{"type":"array","items":{"$ref":"#/components/schemas/MarketReward"}},"clob_rewards":{"type":"array","items":{"$ref":"#/components/schemas/ClobReward"}},"tags":{"type":"array","items":{"type":"string"}},"event_slug":{"type":["string","null"]},"resolution_source":{"type":["string","null"]},"metrics":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/SimpleTimeframeMetrics"},"propertyNames":{"type":"string"}},"relevance_score":{"type":["number","null"],"format":"double"}}}}}},"404":{"description":"Market not found"}}}},"/polymarket/order-book":{"get":{"tags":["Order Book"],"summary":"Get order book","description":"Returns the latest CLOB orderbook snapshot for a position, including derived metrics (best bid/ask, mid price, spread, liquidity depth). Data is sourced from the real-time Polymarket WebSocket feed. `bids` and `asks` are arrays of `{\"p\": price, \"s\": size}` objects, sorted best-first.","operationId":"get_order_book","parameters":[{"name":"position_id","in":"query","description":"Token ID (position ID) to query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Latest orderbook snapshot. ts is Unix milliseconds.","content":{"application/json":{"schema":{"type":"object","required":["ts","position_id","condition_id","bids","asks","hash"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"bids":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"asks":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"hash":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}}}}},"400":{"description":"Missing or invalid parameters"}}}},"/polymarket/order-book/history":{"get":{"tags":["Order Book"],"summary":"Get order book history","description":"Paginated history of raw CLOB orderbook snapshots including full bids/asks levels and derived metrics. Default limit 20, max 200. `bids` and `asks` are arrays of `{\"p\": price, \"s\": size}` objects, sorted best-first.","operationId":"get_order_book_history","parameters":[{"name":"position_id","in":"query","description":"Token ID (required if condition_id / market_slug not set)","required":false,"schema":{"type":"string"}},{"name":"condition_id","in":"query","description":"Condition ID — returns history for all positions in this market","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (alternative to condition_id)","required":false,"schema":{"type":"string"}},{"name":"from","in":"query","description":"Start timestamp (Unix milliseconds, inclusive)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (Unix milliseconds, inclusive)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"min_spread","in":"query","description":"Only return snapshots with spread >= this value","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_spread","in":"query","description":"Only return snapshots with spread <= this value","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_liquidity","in":"query","description":"Only return snapshots where total liquidity (bid + ask) >= this value","required":false,"schema":{"type":"number","format":"double"}},{"name":"limit","in":"query","description":"Number of results (default: 20, max: 200)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"pagination_key","in":"query","description":"Cursor from previous response's pagination.pagination_key","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Orderbook snapshot rows, newest first. ts is Unix milliseconds.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","required":["ts","position_id","condition_id","bids","asks","hash"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"bids":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"asks":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"hash":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}}}}}},"400":{"description":"Missing or invalid parameters"}}}},"/polymarket/order-book/market":{"get":{"tags":["Order Book"],"summary":"Get order books for a market","description":"Returns the latest orderbook snapshot for every position (outcome) in a market. Accepts condition_id or market_slug. `bids` and `asks` are arrays of `{\"p\": price, \"s\": size}` objects, sorted best-first.","operationId":"get_market_order_book","parameters":[{"name":"condition_id","in":"query","description":"Condition ID of the market","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (alternative to condition_id)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Latest orderbook snapshot per position. ts is Unix milliseconds.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","required":["ts","position_id","condition_id","bids","asks","hash"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"bids":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"asks":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"hash":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}}}}}},"400":{"description":"Missing or invalid parameters"}}}},"/polymarket/order-book/spread":{"get":{"tags":["Order Book"],"summary":"Get spread history","description":"Lightweight time series of derived orderbook metrics (best bid/ask, mid price, spread, liquidity depth) without raw bids/asks — ideal for charting. Default limit 20, max 200.","operationId":"get_spread_history","parameters":[{"name":"position_id","in":"query","description":"Token ID (required if condition_id / market_slug not set)","required":false,"schema":{"type":"string"}},{"name":"condition_id","in":"query","description":"Condition ID — returns spread history for all positions in this market","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (alternative to condition_id)","required":false,"schema":{"type":"string"}},{"name":"from","in":"query","description":"Start timestamp (Unix milliseconds, inclusive)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (Unix milliseconds, inclusive)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"min_spread","in":"query","description":"Only return rows with spread >= this value","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_spread","in":"query","description":"Only return rows with spread <= this value","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_liquidity","in":"query","description":"Only return rows where total liquidity (bid + ask) >= this value","required":false,"schema":{"type":"number","format":"double"}},{"name":"limit","in":"query","description":"Number of results (default: 100, max: 1000)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"pagination_key","in":"query","description":"Cursor from previous response's pagination.pagination_key","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Spread time series rows, newest first. ts is Unix milliseconds.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","description":"Lightweight row — derived metrics only, no bids/asks JSONB.","required":["ts","position_id","condition_id"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}}}}}},"400":{"description":"Missing or invalid parameters"}}}},"/polymarket/search":{"get":{"tags":["Search"],"summary":"Search events, markets, and traders","description":"Search across markets, events, and traders. Use `type` to limit which categories are searched. Trader search supports wallet address lookup or name search. Results for each category are independently paginated. Only requested categories are included in the response.","operationId":"search","parameters":[{"name":"q","in":"query","description":"Search query (min 2 characters). Prefix with 0x for exact wallet address lookup.","required":true,"schema":{"type":"string"}},{"name":"type","in":"query","description":"Comma-separated categories to search: events, markets, traders (default: all three, 1 credit per type). Example: type=markets,traders","required":false,"schema":{"type":"string"}},{"name":"include_pnl","in":"query","description":"Include lifetime PnL summary for each trader (default: false, +1 credit)","required":false,"schema":{"type":"boolean"}},{"name":"sort_by","in":"query","description":"Sort field applied to both events and markets (default: volume). Fields marked events-only or markets-only fall back to volume on the other category.","required":false,"schema":{"$ref":"#/components/schemas/SearchSortBy"}},{"name":"sort_dir","in":"query","description":"Sort direction (default: desc)","required":false,"schema":{"$ref":"#/components/schemas/SortDirection"}},{"name":"timeframe","in":"query","description":"Metrics timeframe used for volume/txns/unique_traders sort (default: 24h)","required":false,"schema":{"$ref":"#/components/schemas/MetricsTimeframe"}},{"name":"limit","in":"query","description":"Results limit per category (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"events_pagination_key","in":"query","description":"Cursor for the next page of events, obtained from previous response's events_pagination.pagination_key","required":false,"schema":{"type":"string"}},{"name":"markets_pagination_key","in":"query","description":"Cursor for the next page of markets, obtained from previous response's markets_pagination.pagination_key","required":false,"schema":{"type":"string"}},{"name":"traders_pagination_key","in":"query","description":"Cursor for the next page of traders, obtained from previous response's traders_pagination.pagination_key","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Search results. Only requested categories (via `type`) are included in the response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchResponse"}}}},"400":{"description":"Bad request — q is missing or shorter than 2 characters"}}}},"/polymarket/series":{"get":{"tags":["Series"],"summary":"List or get series","description":"Retrieve series. Use `id` or `series_slug` for single lookup, `series_ids` or `series_slugs` (comma-separated, max 250, mutually exclusive) for multi-lookup, or paginate with `active_only`.","operationId":"get_series_list","parameters":[{"name":"id","in":"query","description":"Single series ID for direct lookup","required":false,"schema":{"type":"string"}},{"name":"series_ids","in":"query","description":"Comma-separated series IDs (max 250). Mutually exclusive with series_slugs.","required":false,"schema":{"type":"string"}},{"name":"series_slugs","in":"query","description":"Comma-separated series slugs (max 250). Mutually exclusive with series_ids.","required":false,"schema":{"type":"string"}},{"name":"active_only","in":"query","description":"Only active series (default: true). Ignored when series_ids or series_slugs are provided.","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor for pagination: id of the last series from the previous page","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Series or list of series","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PolymarketSeries"}}}}},"400":{"description":"series_ids and series_slugs cannot both be provided"}}}},"/polymarket/series/outcomes":{"get":{"tags":["Series"],"summary":"Get series market outcomes","description":"Returns the winning outcome name for each resolved market across all events in a series, keyed by market slug. Useful for checking historical results across recurring series (e.g., btc-updown-5m).","operationId":"get_series_outcomes","parameters":[{"name":"series_slug","in":"query","description":"Series slug (required)","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Number of resolved markets per page (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key for fetching next page","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Map of market_slug → winning outcome name with pagination metadata","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}}}}},"400":{"description":"Missing series_slug parameter"}}}},"/polymarket/tags":{"get":{"tags":["Tags"],"summary":"Get tags","description":"Retrieve all available event tags/categories. Uses cursor-based pagination for efficient traversal.","operationId":"get_tags","parameters":[{"name":"limit","in":"query","description":"Results limit (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of all tags","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PolymarketTag"}}}}}}}},"/polymarket/tags/{identifier}":{"get":{"tags":["Tags"],"summary":"Get tag by slug","description":"Retrieve a single tag by its ID or slug","operationId":"get_tag_by_id","parameters":[{"name":"identifier","in":"path","description":"Tag ID or slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Tag details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PolymarketTag"}}}},"404":{"description":"Tag not found"}}}},"/polymarket/trader/global_pnl":{"get":{"tags":["Trader"],"summary":"Get global leaderboard","description":"Retrieve the global PnL leaderboard ranked by profit and loss. Uses cursor-based pagination for efficient traversal of large datasets.","operationId":"get_global_pnl","parameters":[{"name":"timeframe","in":"query","description":"Timeframe: 1d, 7d, 30d, lifetime (default: lifetime)","required":false,"schema":{"$ref":"#/components/schemas/PnlTimeframe"}},{"name":"sort_by","in":"query","description":"Sort: realized_pnl_usd, buys, sells, redemptions, merges, avg_hold_time, markets_traded, events_traded, markets_won, volume_usd, fees, best_trade (default: realized_pnl_usd)","required":false,"schema":{"$ref":"#/components/schemas/GlobalPnlSortBy"}},{"name":"sort_direction","in":"query","description":"Sort direction: asc, desc (default: desc)","required":false,"schema":{"$ref":"#/components/schemas/SortDirection"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 200)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Global PnL leaderboard with trader stats. Response includes `pagination: { has_more, pagination_key }` for cursor-based pagination.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GlobalPnlTrader"}}}}}}}},"/polymarket/trader/pnl/{address}":{"get":{"tags":["Trader"],"summary":"Get trader PnL summary","description":"Retrieve a trader's overall profit and loss summary","operationId":"get_trader_pnl","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"timeframe","in":"query","description":"Timeframe: 1d, 7d, 30d, lifetime (default: lifetime)","required":false,"schema":{"$ref":"#/components/schemas/PnlTimeframe"}}],"responses":{"200":{"description":"Trader's global PnL summary","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TraderPnlSummary"}}}}}}},"/polymarket/trader/pnl/{address}/calendar":{"get":{"tags":["Trader"],"summary":"Get trader PnL calendar","description":"Retrieve raw per-day PnL. Each entry is the realized PnL for that calendar day. Paginate backwards using the pagination key.","operationId":"get_trader_pnl_calendar","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"days","in":"query","description":"Window size in days (default: 30, max: 30)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Pagination key obtained from a previous response to fetch an earlier window","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Daily PnL entries (one per active trading day)","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PnlCandleEntry"}}}}}}}},"/polymarket/trader/pnl/{address}/candles":{"get":{"tags":["Trader"],"summary":"Get trader PnL candles","description":"Retrieve PnL candles for charting a trader's equity curve over time.","operationId":"get_trader_pnl_candles","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Candle resolution (default: 1h)","required":false,"schema":{"$ref":"#/components/schemas/PnlCandleResolution"}},{"name":"timeframe","in":"query","description":"Time range (default: lifetime)","required":false,"schema":{"$ref":"#/components/schemas/PnlCandleTimeframe"}}],"responses":{"200":{"description":"Cumulative PnL candles","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PnlCandleEntry"}}}}}}}},"/polymarket/trader/pnl/{address}/events":{"get":{"tags":["Trader"],"summary":"Get trader event PnL","description":"Retrieve event-level PnL breakdown for a trader","operationId":"get_trader_event_pnl","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"timeframe","in":"query","description":"Timeframe: 1d, 7d, 30d, lifetime (default: lifetime)","required":false,"schema":{"$ref":"#/components/schemas/PnlTimeframe"}},{"name":"sort_by","in":"query","description":"Sort: realized_pnl_usd, total_volume_usd, markets_traded, total_fees (default: realized_pnl_usd)","required":false,"schema":{"$ref":"#/components/schemas/EventPnlSortBy"}},{"name":"sort_direction","in":"query","description":"Sort direction: asc, desc (default: desc)","required":false,"schema":{"$ref":"#/components/schemas/SortDirection"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 200)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"offset","in":"query","description":"Pagination offset (number of results to skip). Takes precedence over pagination_key.","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key obtained from previous response's pagination.pagination_key","required":false,"schema":{"type":"string"}},{"name":"event_slug","in":"query","description":"Filter by event slug","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Event-level PnL entries for this trader","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TraderEventPnlEntry"}}}}}}}},"/polymarket/trader/pnl/{address}/markets":{"get":{"tags":["Trader"],"summary":"Get trader market PnL","description":"Retrieve market-level PnL breakdown for a trader","operationId":"get_trader_market_pnl","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"timeframe","in":"query","description":"Timeframe: 1d, 7d, 30d, lifetime (default: lifetime)","required":false,"schema":{"$ref":"#/components/schemas/PnlTimeframe"}},{"name":"sort_by","in":"query","description":"Sort: realized_pnl_usd, buy_usd, total_buys, total_fees, outcomes_traded (default: realized_pnl_usd)","required":false,"schema":{"$ref":"#/components/schemas/MarketPnlSortBy"}},{"name":"sort_direction","in":"query","description":"Sort direction: asc, desc (default: desc)","required":false,"schema":{"$ref":"#/components/schemas/SortDirection"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 200)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"offset","in":"query","description":"Pagination offset (number of results to skip). Takes precedence over pagination_key.","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key obtained from previous response's pagination.pagination_key","required":false,"schema":{"type":"string"}},{"name":"condition_id","in":"query","description":"Filter by condition ID (or use market_slug)","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Filter by market slug (alternative to condition_id)","required":false,"schema":{"type":"string"}},{"name":"event_slug","in":"query","description":"Filter by event slug","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Market-level PnL entries for this trader","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TraderMarketPnlEntry"}}}}}}}},"/polymarket/trader/pnl/{address}/positions":{"get":{"tags":["Trader"],"summary":"Get trader position PnL","description":"Retrieve per-outcome-token lifetime PnL for a trader from polymarket_accounts. Includes open/closed state, win/loss outcome, redemption payouts, and share quantities. Filter by status and won/lost to segment portfolio views.","operationId":"get_trader_position_pnl","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Required. Filter by position status","required":true,"schema":{"type":"string","enum":["open","closed"]}},{"name":"won","in":"query","description":"Filter by outcome: true (won), false (lost), only for status=closed","required":false,"schema":{"type":"boolean"}},{"name":"search","in":"query","description":"Search by market title","required":false,"schema":{"type":"string"}},{"name":"sort_by","in":"query","description":"Sort field (default: realized_pnl_usd)","required":false,"schema":{"$ref":"#/components/schemas/PositionPnlSortBy"}},{"name":"sort_direction","in":"query","description":"Sort direction: asc, desc (default: desc)","required":false,"schema":{"$ref":"#/components/schemas/SortDirection"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 200)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"offset","in":"query","description":"Pagination offset","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"condition_id","in":"query","description":"Filter by market condition ID (or use market_slug)","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Filter by market slug (alternative to condition_id)","required":false,"schema":{"type":"string"}},{"name":"position_id","in":"query","description":"Filter by specific outcome token (position ID)","required":false,"schema":{"type":"string"}},{"name":"min_shares","in":"query","description":"Minimum shares balance to include (e.g. 1.0 to filter out dust positions)","required":false,"schema":{"type":"number","format":"double"}}],"responses":{"200":{"description":"Position-level PnL entries for this trader. Each entry is a specific outcome token with open/closed state, avg_entry_price, avg_exit_price, and redemption info.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TraderOutcomePnlEntry"}}}}}}}},"/polymarket/trader/profile/{address}":{"get":{"tags":["Trader"],"summary":"Get trader overview","description":"Retrieve a trader's profile including stats and trading history summary","operationId":"get_trader_profile","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Trader profile information with username, bio, and badges","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PolymarketUserProfile"}}}}}}},"/polymarket/trader/profiles/batch":{"get":{"tags":["Trader"],"summary":"Get multiple trader profiles","description":"Retrieve profiles for multiple traders in a single request. Returns an array of profiles.","operationId":"get_trader_profiles_batch","parameters":[{"name":"addresses","in":"query","description":"Comma-separated list of trader addresses (max: 20)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Array of trader profiles","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PolymarketUserProfile"}}}}},"400":{"description":"Invalid request (empty addresses or more than 20)"}}}},"/polymarket/trader/trades/{address}":{"get":{"tags":["Trader"],"summary":"Get trader trades","description":"Retrieve trade history for a specific trader across all markets","operationId":"get_trader_trades","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"condition_ids","in":"query","description":"Comma-separated condition IDs (max 20)","required":false,"schema":{"type":"string"}},{"name":"slugs","in":"query","description":"Comma-separated market slugs","required":false,"schema":{"type":"string"}},{"name":"position_ids","in":"query","description":"Comma-separated position IDs","required":false,"schema":{"type":"string"}},{"name":"side","in":"query","description":"Trade side: 0 (Buy), 1 (Sell)","required":false,"schema":{"$ref":"#/components/schemas/TradeSide"}},{"name":"outcome","in":"query","description":"Outcome name filter (e.g. Yes, No)","required":false,"schema":{"type":"string"}},{"name":"outcome_index","in":"query","description":"Outcome index: 0 (Yes), 1 (No)","required":false,"schema":{"$ref":"#/components/schemas/OutcomeIndex"}},{"name":"trade_types","in":"query","description":"Comma-separated trade types: OrderFilled, Redemption, Merge, Split, Cancelled, PositionsConverted, OrdersMatched","required":false,"schema":{"type":"string"}},{"name":"min_usd_amount","in":"query","description":"Min USD amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_usd_amount","in":"query","description":"Max USD amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_shares_amount","in":"query","description":"Min shares amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_shares_amount","in":"query","description":"Max shares amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_price","in":"query","description":"Min price (0.0-1.0)","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_price","in":"query","description":"Max price (0.0-1.0)","required":false,"schema":{"type":"number","format":"double"}},{"name":"from","in":"query","description":"Start timestamp (ms)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (ms)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"all","in":"query","description":"Return all-time trades, not just last 30 days (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Results per page (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32","minimum":0}},{"name":"offset","in":"query","description":"Pagination offset (number of results to skip). Takes precedence over pagination_key.","required":false,"schema":{"type":"integer","format":"int32","minimum":0}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key obtained from previous response's pagination.pagination_key","required":false,"schema":{"type":"string"}},{"name":"sort_desc","in":"query","description":"Sort newest first (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Trader's trade history with advanced filtering (same as /market/trades but filtered by trader)","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PredictionTradeResponse"}}}}}}}},"/polymarket/trader/volume-chart/{address}":{"get":{"tags":["Trader"],"summary":"Get trader volume chart","description":"Retrieve volume breakdown by buy/sell over time for a specific trader","operationId":"get_trader_volume_chart","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Time interval: 1, 5, 15, 30, 60, 240, D, 1D (default: 60)","required":false,"schema":{"$ref":"#/components/schemas/CandlestickResolution"}},{"name":"count_back","in":"query","description":"Number of data points (max: 2500)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"from","in":"query","description":"Start timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Trader volume with buy/sell breakdown over time","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TraderVolumeDataPoint"}}}}}}}}},"components":{"schemas":{"AssetPriceHistoryRow":{"type":"object","description":"A single asset price history record from the `asset_price_history` table.","required":["asset_symbol","asset_open_price","asset_close_price","variant","start_time","end_time"],"properties":{"asset_symbol":{"type":"string"},"asset_open_price":{"type":"number","format":"double","description":"Opening price at start_time (cast to f64 from NUMERIC in query)"},"asset_close_price":{"type":"number","format":"double","description":"Closing price at end_time (cast to f64 from NUMERIC in query)"},"price_change_percentage":{"type":["number","null"],"format":"double"},"outcome":{"type":["string","null"],"description":"Generated column: \"up\" if close > open, \"down\" if close ≤ open, null if no close yet"},"variant":{"type":"string","description":"Time window: \"5m\", \"15m\", \"1h\", \"1d\""},"start_time":{"type":"integer","format":"int64","description":"Window start timestamp (seconds since epoch)"},"end_time":{"type":"integer","format":"int64","description":"Window end timestamp (seconds since epoch)"}}},"AssetSymbol":{"type":"string","enum":["BTC","ETH","XRP","SOL","DOGE","BNB","HYPE"]},"AssetVariant":{"type":"string","enum":["5m","15m","1h","4h","1d"]},"BondMarket":{"type":"object","required":["condition_id","question","market_slug","end_time","best_outcome_index","return_pct","apy","outcomes"],"properties":{"condition_id":{"type":"string"},"title":{"type":["string","null"]},"question":{"type":"string"},"market_slug":{"type":"string"},"event_slug":{"type":["string","null"]},"image_url":{"type":["string","null"]},"end_time":{"type":"integer","format":"int64"},"best_outcome_index":{"type":"integer","format":"int32","minimum":0},"return_pct":{"type":"number","format":"double"},"apy":{"type":"number","format":"double"},"volume_24h":{"type":["number","null"],"format":"double"},"outcomes":{"type":"array","items":{"$ref":"#/components/schemas/BondOutcome"}}}},"BondOutcome":{"type":"object","required":["name","index","position_id","price"],"properties":{"name":{"type":"string"},"index":{"type":"integer","format":"int32"},"position_id":{"type":"string"},"price":{"type":"number","format":"double"}}},"CandlestickResolution":{"type":"string","enum":["1","5","15","30","60","240","D","1D"]},"ChartResolution":{"type":"string","enum":["1H","6H","1D","1W","1M","ALL"]},"ClobReward":{"type":"object","description":"CLOB reward (public API format)","required":["id","condition_id"],"properties":{"id":{"type":"string"},"condition_id":{"type":"string"},"asset_address":{"type":["string","null"]},"rewards_amount":{"type":["number","null"],"format":"double"},"rewards_daily_rate":{"type":["number","null"],"format":"double"},"start_date":{"type":["string","null"]},"end_date":{"type":["string","null"]},"rewards_max_spread":{"type":["number","null"],"format":"double"},"rewards_min_size":{"type":["number","null"],"format":"double"},"native_daily_rate":{"type":["number","null"],"format":"double"},"sponsored_daily_rate":{"type":["number","null"],"format":"double"},"total_daily_rate":{"type":["number","null"],"format":"double"},"sponsors_count":{"type":["integer","null"],"format":"int32"}}},"ConditionMetricsResponse":{"type":"object","description":"Response type for condition metrics query","required":["condition_id","timeframe","volume_usd","fees","txns","unique_traders"],"properties":{"condition_id":{"type":"string"},"timeframe":{"type":"string"},"volume_usd":{"type":"number","format":"double"},"fees":{"type":"number","format":"double"},"txns":{"type":"integer","format":"int32"},"unique_traders":{"type":"integer","format":"int32"}}},"ConditionOrderbookRow":{"type":"object","required":["ts","position_id","condition_id","bids","asks","hash"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"bids":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"asks":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"hash":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}},"EventMarket":{"type":"object","description":"Enriched market data for event API responses","properties":{"condition_id":{"type":"string","default":""},"id":{"type":["string","null"],"default":null},"title":{"type":["string","null"],"default":null},"question":{"type":"string","default":""},"market_slug":{"type":"string","default":""},"status":{"type":"string","default":""},"created_time":{"type":["integer","null"],"format":"int64","default":null},"end_time":{"type":["integer","null"],"format":"int64","default":null},"volume":{"type":["number","null"],"format":"double","default":null},"liquidity_usd":{"type":["number","null"],"format":"double","default":null},"volume_24hr":{"type":["number","null"],"format":"double","default":null},"image_url":{"type":["string","null"],"default":null},"market_maker_address":{"type":["string","null"],"default":null},"creator":{"type":["string","null"],"default":null},"category":{"type":["string","null"],"default":null},"accepting_orders":{"type":["boolean","null"],"default":null},"uma_resolution_status":{"type":["string","null"],"default":null},"clob_rewards":{"type":"array","items":{"$ref":"#/components/schemas/ClobReward"},"default":[]},"outcomes":{"type":"array","items":{"$ref":"#/components/schemas/EventMarketOutcome"},"default":[]},"winning_outcome":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/EventMarketOutcome"}],"default":null}}},"EventMarketChartDataPoint":{"type":"object","required":["v","t"],"properties":{"v":{"type":"number","format":"double"},"t":{"type":"integer","format":"int64","minimum":0}}},"EventMarketChartOutcome":{"type":"object","required":["condition_id","market_slug","question","title","data"],"properties":{"condition_id":{"type":"string"},"market_slug":{"type":"string"},"question":{"type":"string"},"title":{"type":"string"},"data":{"type":"array","items":{"$ref":"#/components/schemas/EventMarketChartDataPoint"}}}},"EventMarketOutcome":{"type":"object","description":"Market outcome for event API responses","required":["name"],"properties":{"name":{"type":"string"},"price":{"type":["number","null"],"format":"double"},"position_id":{"type":["string","null"]},"outcome_index":{"type":["integer","null"],"format":"int32"}}},"EventMetricsResponse":{"type":"object","description":"Response type for event metrics query","required":["event_slug","timeframe","volume_usd","fees","txns","unique_traders"],"properties":{"event_slug":{"type":"string"},"timeframe":{"type":"string"},"volume_usd":{"type":"number","format":"double"},"fees":{"type":"number","format":"double"},"txns":{"type":"integer","format":"int32"},"unique_traders":{"type":"integer","format":"int32"}}},"EventPnlSortBy":{"type":"string","enum":["realized_pnl_usd","total_volume_usd","markets_traded","total_fees","realized_pnl_pct"]},"EventSortBy":{"type":"string","enum":["volume","txns","unique_traders","title","creation_date","start_date","end_date","relevance"]},"GlobalPnlSortBy":{"type":"string","enum":["realized_pnl_usd","buys","sells","redemptions","merges","avg_hold_time","markets_traded","events_traded","markets_won","volume_usd","fees","best_trade"]},"GlobalPnlTrader":{"type":"object","description":"Individual trader entry in the global PnL leaderboard","required":["trader"],"properties":{"trader":{"$ref":"#/components/schemas/TraderInfo"},"realized_pnl_usd":{"type":["number","null"],"format":"double"},"events_traded":{"type":["integer","null"],"format":"int64"},"markets_traded":{"type":["integer","null"],"format":"int64"},"markets_won":{"type":["integer","null"],"format":"int64"},"markets_lost":{"type":["integer","null"],"format":"int64"},"market_win_rate_pct":{"type":["number","null"],"format":"double"},"total_volume_usd":{"type":["number","null"],"format":"double"},"buy_volume_usd":{"type":["number","null"],"format":"double"},"sell_volume_usd":{"type":["number","null"],"format":"double"},"redemption_volume_usd":{"type":["number","null"],"format":"double"},"merge_volume_usd":{"type":["number","null"],"format":"double"},"total_buys":{"type":["integer","null"],"format":"int64"},"total_sells":{"type":["integer","null"],"format":"int64"},"total_redemptions":{"type":["integer","null"],"format":"int64"},"total_merges":{"type":["integer","null"],"format":"int64"},"total_trades":{"type":["integer","null"],"format":"int64"},"total_fees":{"type":["number","null"],"format":"double"},"avg_pnl_per_market":{"type":["number","null"],"format":"double"},"avg_pnl_per_trade":{"type":["number","null"],"format":"double"},"avg_hold_time_seconds":{"type":["number","null"],"format":"double"},"best_trade_pnl_usd":{"type":["number","null"],"format":"double"},"best_trade_condition_id":{"type":["string","null"]},"first_trade_at":{"type":["integer","null"],"format":"int64"},"last_trade_at":{"type":["integer","null"],"format":"int64"}}},"Holder":{"type":"object","description":"Individual holder data","required":["trader","shares"],"properties":{"trader":{"$ref":"#/components/schemas/Trader","description":"Trader profile information"},"shares":{"type":"string","description":"Position shares held (raw balance as string for precision)"},"shares_usd":{"type":["string","null"],"description":"USD value of shares (shares * latest price)"},"usd_balance":{"type":["string","null"],"description":"USD balance of wallet (USDe on Polygon)"},"pnl":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/HolderPnl","description":"Holder-level PnL, included only when `include_pnl=true`"}]}}},"HolderHistoryCandle":{"type":"object","description":"Holder statistics data point (single time bucket)","required":["t"],"properties":{"t":{"type":"integer","format":"int64"},"h":{"type":["integer","null"],"format":"int64"}}},"HolderPnl":{"type":"object","description":"Holder-level PnL data, included when `include_pnl=true`","properties":{"avg_entry_price":{"type":["number","null"],"format":"double"},"total_cost_usd":{"type":["string","null"]},"unrealized_pnl_usd":{"type":["string","null"]},"realized_sell_pnl_usd":{"type":["string","null"]},"avg_exit_price":{"type":["number","null"],"format":"double"},"buy_usd":{"type":["number","null"],"format":"double"},"sell_usd":{"type":["number","null"],"format":"double"},"total_buys":{"type":["integer","null"],"format":"int64"},"total_sells":{"type":["integer","null"],"format":"int64"},"total_fees":{"type":["number","null"],"format":"double"},"first_trade_at":{"type":["integer","null"],"format":"int64"},"last_trade_at":{"type":["integer","null"],"format":"int64"}}},"MarketHoldersResponse":{"type":"object","description":"Response for market (condition_id) holders endpoint","required":["condition_id","total_holders","outcomes"],"properties":{"condition_id":{"type":"string","description":"Market condition ID"},"question":{"type":["string","null"],"description":"Market question/title"},"slug":{"type":["string","null"],"description":"Market slug"},"total_holders":{"type":"integer","format":"int64","description":"Total unique holders across all outcomes (from holder_stats)"},"outcomes":{"type":"array","items":{"$ref":"#/components/schemas/OutcomeHolders"},"description":"Holders grouped by outcome"}}},"MarketMetadata":{"type":"object","description":"Market metadata (enriched, cached version)","required":["condition_id","question","description","slug","neg_risk","tokens","tags","outcomes","metrics","clob_rewards"],"properties":{"condition_id":{"type":"string"},"question":{"type":"string"},"description":{"type":"string"},"slug":{"type":"string"},"event_slug":{"type":["string","null"]},"event_id":{"type":["string","null"]},"event_title":{"type":["string","null"]},"series_slug":{"type":["string","null"]},"neg_risk":{"type":"boolean"},"tokens":{"type":"array","items":{"$ref":"#/components/schemas/TokenOutcome"}},"image_url":{"type":["string","null"]},"tags":{"type":"array","items":{"type":"string"}},"created_time":{"type":["integer","null"],"format":"int64"},"start_time":{"type":["integer","null"],"format":"int64"},"game_start_time":{"type":["integer","null"],"format":"int64"},"closed_time":{"type":["integer","null"],"format":"int64"},"end_time":{"type":["integer","null"],"format":"int64"},"title":{"type":["string","null"]},"id":{"type":["string","null"]},"volume_usd":{"type":["number","null"],"format":"double"},"liquidity_usd":{"type":["number","null"],"format":"double"},"outcomes":{"type":"array","items":{"$ref":"#/components/schemas/MarketOutcome"}},"metrics":{"type":"object","additionalProperties":{"type":"number","format":"double"},"propertyNames":{"type":"string"}},"market_maker_address":{"type":["string","null"]},"creator":{"type":["string","null"]},"category":{"type":["string","null"]},"clob_rewards":{"type":"array","items":{"$ref":"#/components/schemas/ClobReward"}}}},"MarketMetadataOutcome":{"type":"object","description":"Market outcome with timeframe metrics (websocket API format)","required":["token_id","outcome"],"properties":{"token_id":{"type":"string"},"outcome":{"type":"string"},"last_price":{"type":["number","null"],"format":"double"},"last_probability":{"type":["number","null"],"format":"double"},"metrics":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/OutcomeTimeframeMetrics"},"propertyNames":{"type":"string"}}}},"MarketOutcome":{"type":"object","description":"Outcome for market API responses","properties":{"name":{"type":"string","default":""},"price":{"type":["number","null"],"format":"double","default":null},"position_id":{"type":["string","null"],"default":null},"outcome_index":{"type":["integer","null"],"format":"int32","default":null}}},"MarketPnlSortBy":{"type":"string","enum":["realized_pnl_usd","buy_usd","total_buys","total_fees","outcomes_traded","realized_pnl_pct"]},"MarketResponse":{"type":"object","description":"Formatted market response with structured metrics, tags, outcomes, and event","required":["condition_id","status"],"properties":{"condition_id":{"type":"string"},"id":{"type":["string","null"]},"market_slug":{"type":["string","null"]},"question":{"type":["string","null"]},"title":{"type":["string","null"]},"description":{"type":["string","null"]},"image_url":{"type":["string","null"]},"oracle":{"type":["string","null"]},"status":{"type":"string"},"created_time":{"type":["integer","null"],"format":"int64"},"start_time":{"type":["integer","null"],"format":"int64"},"game_start_time":{"type":["integer","null"],"format":"int64"},"closed_time":{"type":["integer","null"],"format":"int64"},"end_time":{"type":["integer","null"],"format":"int64"},"accepting_orders":{"type":["boolean","null"]},"uma_resolution_status":{"type":["string","null"]},"is_neg_risk":{"type":["boolean","null"]},"market_maker_address":{"type":["string","null"]},"creator":{"type":["string","null"]},"category":{"type":["string","null"]},"volume_usd":{"type":["number","null"],"format":"double"},"liquidity_usd":{"type":["number","null"],"format":"double"},"highest_probability":{"type":["number","null"],"format":"double"},"total_holders":{"type":["integer","null"],"format":"int64"},"winning_outcome":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/MarketOutcome"}]},"outcomes":{"type":"array","items":{"$ref":"#/components/schemas/MarketOutcome"}},"rewards":{"type":"array","items":{"$ref":"#/components/schemas/MarketReward"}},"clob_rewards":{"type":"array","items":{"$ref":"#/components/schemas/ClobReward"}},"tags":{"type":"array","items":{"type":"string"}},"event_slug":{"type":["string","null"]},"resolution_source":{"type":["string","null"]},"metrics":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/SimpleTimeframeMetrics"},"propertyNames":{"type":"string"}},"relevance_score":{"type":["number","null"],"format":"double"}}},"MarketReward":{"type":"object","description":"Reward info for market API responses","properties":{"min_size":{"type":["number","null"],"format":"double","default":null},"max_spread":{"type":["number","null"],"format":"double","default":null},"daily_rate":{"type":["number","null"],"format":"double","default":null}}},"MarketSortBy":{"type":"string","enum":["volume","txns","unique_traders","liquidity","holders","end_time","start_time","created_time","relevance"]},"MarketStatus":{"type":"string","enum":["open","closed","all"]},"MarketVolumeChartResponse":{"type":"object","required":["volumes","has_more"],"properties":{"volumes":{"type":"array","items":{"$ref":"#/components/schemas/MarketVolumeDataPoint"}},"has_more":{"type":"boolean"}}},"MarketVolumeDataPoint":{"type":"object","required":["t","v","yv","nv","tc","ytc","ntc"],"properties":{"t":{"type":"integer","format":"int64"},"v":{"type":"number","format":"double"},"yv":{"type":"number","format":"double"},"nv":{"type":"number","format":"double"},"tc":{"type":"integer","format":"int32"},"ytc":{"type":"integer","format":"int32"},"ntc":{"type":"integer","format":"int32"}}},"MetricsTimeframe":{"type":"string","enum":["1m","5m","30m","1h","6h","24h","7d","30d"]},"OrderbookHistoryRow":{"type":"object","required":["ts","position_id","condition_id","bids","asks","hash"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"bids":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"asks":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"hash":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}},"OrderbookLevel":{"type":"object","description":"A single price level in a bids/asks array.","required":["p","s"],"properties":{"p":{"type":"string","description":"Price as a decimal string"},"s":{"type":"string","description":"Size as a decimal string"}}},"OrderbookSnapshotRow":{"type":"object","required":["ts","position_id","condition_id","bids","asks","hash"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"bids":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"asks":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"hash":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}},"OutcomeHolders":{"type":"object","description":"Holder data grouped by outcome for market-level queries","required":["outcome_index","outcome_name","position_id","total_holders","holders"],"properties":{"outcome_index":{"type":"integer","format":"int32","description":"Outcome index (0, 1, etc.)"},"outcome_name":{"type":"string","description":"Outcome name (Yes, No, etc.)"},"position_id":{"type":"string","description":"Position ID for this outcome"},"price":{"type":["number","null"],"format":"double","description":"Current price/probability"},"total_holders":{"type":"integer","format":"int64","description":"Total holders count from holder_stats"},"holders":{"type":"array","items":{"$ref":"#/components/schemas/Holder"},"description":"Top holders for this outcome"}}},"OutcomeIndex":{"type":"string","enum":["0","1"]},"OutcomeTimeframeMetrics":{"type":"object","properties":{"volume":{"type":"number","format":"double","default":0},"buy_volume":{"type":"number","format":"double","default":0},"sell_volume":{"type":"number","format":"double","default":0},"txns":{"type":"integer","format":"int32","default":0},"buys":{"type":"integer","format":"int32","default":0},"sells":{"type":"integer","format":"int32","default":0},"price_open":{"type":["number","null"],"format":"double","default":null},"price_close":{"type":["number","null"],"format":"double","default":null},"price_high":{"type":["number","null"],"format":"double","default":null},"price_low":{"type":["number","null"],"format":"double","default":null},"probability_open":{"type":["number","null"],"format":"double","default":null},"probability_close":{"type":["number","null"],"format":"double","default":null},"probability_high":{"type":["number","null"],"format":"double","default":null},"probability_low":{"type":["number","null"],"format":"double","default":null},"price_change_percent":{"type":["number","null"],"format":"double","default":null}}},"PaginationMeta":{"type":"object","description":"Pagination metadata to include in API responses","required":["has_more"],"properties":{"has_more":{"type":"boolean","description":"Whether there are more results available"},"pagination_key":{"type":["string","null"],"description":"Pagination key for the next page (if has_more is true)"}}},"PnlCandleEntry":{"type":"object","description":"A single PnL candle entry","required":["t","pnl"],"properties":{"t":{"type":"integer","format":"int64","description":"Timestamp in epoch seconds (start of bucket window)"},"pnl":{"type":"number","format":"double","description":"Realized PnL in this bucket (USD)"}}},"PnlCandleResolution":{"type":"string","enum":["1m","1h","1d"]},"PnlCandleTimeframe":{"type":"string","enum":["1d","7d","30d","lifetime"]},"PnlTimeframe":{"type":"string","enum":["1d","7d","30d","lifetime"]},"PolymarketEvent":{"type":"object","description":"A Polymarket event from the Gamma API","properties":{"id":{"type":"string","default":""},"event_slug":{"type":["string","null"],"default":null},"title":{"type":["string","null"],"default":null},"ticker":{"type":["string","null"],"default":null},"description":{"type":["string","null"],"default":null},"resolution_source":{"type":["string","null"],"default":null},"category":{"type":["string","null"],"default":null},"image_url":{"type":["string","null"],"default":null},"market_count":{"type":"integer","format":"int32","default":0},"created_time":{"type":["integer","null"],"format":"int64","default":null},"closed_time":{"type":["integer","null"],"format":"int64","default":null},"start_time":{"type":["integer","null"],"format":"int64","default":null},"end_time":{"type":["integer","null"],"format":"int64","default":null},"neg_risk":{"type":"boolean","default":false},"neg_risk_market_id":{"type":["string","null"],"default":null},"game_status":{"type":["string","null"],"default":null},"show_market_images":{"type":"boolean","default":false},"status":{"type":["string","null"],"description":"Event status: \"open\" or \"closed\"","default":null},"metrics":{"type":"object","default":{},"additionalProperties":{"$ref":"#/components/schemas/SimpleTimeframeMetrics"},"propertyNames":{"type":"string"}},"tags":{"type":"array","items":{"$ref":"#/components/schemas/PolymarketTag"},"default":[]},"markets":{"type":"array","items":{"$ref":"#/components/schemas/EventMarket"},"default":[]},"series":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PolymarketSeries"}],"default":null}}},"PolymarketSeries":{"type":"object","description":"A Polymarket series from the Gamma API\nSeries are parent groupings above events (e.g., \"NBA Season 2024-25\")","properties":{"id":{"type":"string","default":""},"slug":{"type":["string","null"],"default":null},"ticker":{"type":["string","null"],"default":null},"title":{"type":["string","null"],"default":null},"description":{"type":["string","null"],"default":null},"series_type":{"type":["string","null"],"default":null},"recurrence":{"type":["string","null"],"default":null},"layout":{"type":["string","null"],"default":null},"image_url":{"type":["string","null"],"default":null},"icon_url":{"type":["string","null"],"default":null},"active":{"type":"boolean","default":false},"closed":{"type":"boolean","default":false},"archived":{"type":"boolean","default":false},"featured":{"type":"boolean","default":false},"restricted":{"type":"boolean","default":false},"pyth_token_id":{"type":["string","null"],"default":null},"cg_asset_name":{"type":["string","null"],"default":null},"start_date":{"type":["integer","null"],"format":"int64","default":null},"event_count":{"type":"integer","format":"int32","default":0}}},"PolymarketTag":{"type":"object","description":"A Polymarket tag from the Gamma API","properties":{"id":{"type":"string","default":""},"label":{"type":"string","default":""},"slug":{"type":["string","null"],"default":null}}},"PolymarketUserProfile":{"type":"object","description":"Polymarket user profile (public API format)","required":["proxy_wallet","display_username_public","verified_badge","is_creator","is_mod"],"properties":{"proxy_wallet":{"type":"string"},"name":{"type":["string","null"]},"pseudonym":{"type":["string","null"]},"bio":{"type":["string","null"]},"profile_image":{"type":["string","null"]},"x_username":{"type":["string","null"]},"display_username_public":{"type":"boolean"},"verified_badge":{"type":"boolean"},"user_id":{"type":["string","null"]},"is_creator":{"type":"boolean"},"is_mod":{"type":"boolean"},"created_at":{"type":["string","null"]}}},"PositionChartDataPoint":{"type":"object","required":["v","t"],"properties":{"v":{"type":"number","format":"double"},"t":{"type":"integer","format":"int64","minimum":0}}},"PositionChartOutcome":{"type":"object","required":["position_id","name","outcome_index","data"],"properties":{"position_id":{"type":"string"},"name":{"type":"string"},"outcome_index":{"type":"integer","format":"int32"},"data":{"type":"array","items":{"$ref":"#/components/schemas/PositionChartDataPoint"}}}},"PositionHoldersResponse":{"type":"object","description":"Response for position (position_id) holders endpoint","required":["position_id","total_holders","holders"],"properties":{"position_id":{"type":"string","description":"Position ID (ERC1155 token ID)"},"condition_id":{"type":["string","null"],"description":"Condition ID this position belongs to"},"outcome_name":{"type":["string","null"],"description":"Outcome name"},"outcome_index":{"type":["integer","null"],"format":"int32","description":"Outcome index"},"price":{"type":["number","null"],"format":"double","description":"Current price"},"total_holders":{"type":"integer","format":"int64","description":"Total holders count from holder_stats"},"holders":{"type":"array","items":{"$ref":"#/components/schemas/Holder"},"description":"Top holders"}}},"PositionMetricsResponse":{"type":"object","description":"Response type for position metrics query","required":["position_id","condition_id","timeframe","volume_usd","buy_volume_usd","sell_volume_usd","fees","txns","buys","sells","unique_traders","price_open","price_high","price_low","price_close"],"properties":{"position_id":{"type":"string"},"condition_id":{"type":"string"},"timeframe":{"type":"string"},"volume_usd":{"type":"number","format":"double"},"buy_volume_usd":{"type":"number","format":"double"},"sell_volume_usd":{"type":"number","format":"double"},"fees":{"type":"number","format":"double"},"txns":{"type":"integer","format":"int32"},"buys":{"type":"integer","format":"int32"},"sells":{"type":"integer","format":"int32"},"unique_traders":{"type":"integer","format":"int32"},"price_open":{"type":"number","format":"double"},"price_high":{"type":"number","format":"double"},"price_low":{"type":"number","format":"double"},"price_close":{"type":"number","format":"double"}}},"PositionPnlSortBy":{"type":"string","enum":["realized_pnl_usd","buy_usd","sell_usd","redemption_usd","total_buys","total_sells","total_shares_bought","total_shares_sold","avg_entry_price","avg_exit_price","total_fees","first_trade_at","last_trade_at","current_value","realized_pnl_pct","title"]},"PositionStatus":{"type":"string","enum":["open","closed"]},"PositionVolumeChartResponse":{"type":"object","required":["volumes","has_more"],"properties":{"volumes":{"type":"array","items":{"$ref":"#/components/schemas/PositionVolumeDataPoint"}},"has_more":{"type":"boolean"}}},"PositionVolumeDataPoint":{"type":"object","required":["t","v","bv","sv","tc","btc","stc"],"properties":{"t":{"type":"integer","format":"int64"},"v":{"type":"number","format":"double"},"bv":{"type":"number","format":"double"},"sv":{"type":"number","format":"double"},"tc":{"type":"integer","format":"int32"},"btc":{"type":"integer","format":"int32"},"stc":{"type":"integer","format":"int32"}}},"PredictionCandlestickBar":{"type":"object","required":["t"],"properties":{"l":{"type":["number","null"],"format":"double"},"h":{"type":["number","null"],"format":"double"},"o":{"type":["number","null"],"format":"double"},"c":{"type":["number","null"],"format":"double"},"v":{"type":["number","null"],"format":"double"},"t":{"type":"integer","format":"int64","minimum":0},"tc":{"type":["integer","null"],"format":"int32"},"m":{"type":["number","null"],"format":"double"}}},"PredictionTradeResponse":{"type":"object","description":"Response format for prediction trades","required":["id","hash","block","confirmed_at","trader","taker","usd_amount","shares_amount","price","fee","exchange","trade_type","log_index","order_hash","position_id"],"properties":{"id":{"type":"string"},"hash":{"type":"string"},"block":{"type":"integer","format":"int64","minimum":0},"confirmed_at":{"type":"integer","format":"int64","minimum":0},"trader":{"$ref":"#/components/schemas/TraderInfo"},"taker":{"type":"string"},"side":{"type":["string","null"]},"condition_id":{"type":["string","null"]},"outcome":{"type":["string","null"]},"outcome_index":{"type":["integer","null"],"format":"int32"},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"slug":{"type":["string","null"]},"event_slug":{"type":["string","null"]},"usd_amount":{"type":"number","format":"double"},"shares_amount":{"type":"number","format":"double"},"price":{"type":"number","format":"double"},"probability":{"type":["number","null"],"format":"double"},"fee":{"type":"number","format":"double"},"exchange":{"type":"string"},"trade_type":{"type":"string"},"log_index":{"type":"integer","format":"int64","minimum":0},"order_hash":{"type":"string"},"position_id":{"type":"string"}}},"PriceJump":{"type":"object","required":["from","to","price_before","price_after","change_pct","direction","volume","trades_count","condition_id"],"properties":{"from":{"type":"integer","format":"int64","minimum":0},"to":{"type":"integer","format":"int64","minimum":0},"price_before":{"type":"number","format":"double"},"price_after":{"type":"number","format":"double"},"change_pct":{"type":"number","format":"double"},"direction":{"type":"string"},"volume":{"type":"number","format":"double"},"trades_count":{"type":"integer","format":"int32"},"condition_id":{"type":"string"}}},"SearchResponse":{"type":"object","properties":{"events":{"type":["array","null"],"items":{"$ref":"#/components/schemas/PolymarketEvent"}},"events_pagination":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PaginationMeta"}]},"markets":{"type":["array","null"],"items":{"$ref":"#/components/schemas/MarketResponse"}},"markets_pagination":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PaginationMeta"}]},"traders":{"type":["array","null"],"items":{"$ref":"#/components/schemas/TraderWithPnl"}},"traders_pagination":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PaginationMeta"}]}}},"SearchSortBy":{"type":"string","description":"Combined sort options valid for both events and markets in search","enum":["volume","txns","unique_traders","relevance","title","creation_date","start_date","end_date","liquidity","holders","end_time","start_time","created_time"]},"SimpleTimeframeMetrics":{"type":"object","properties":{"volume":{"type":"number","format":"double","default":0},"fees":{"type":"number","format":"double","default":0},"txns":{"type":"integer","format":"int32","default":0},"unique_traders":{"type":"integer","format":"int32","default":0}}},"SortDirection":{"type":"string","enum":["asc","desc"]},"SpikeDirection":{"type":"string","description":"Direction filter for spike webhooks.","enum":["up","down","both"]},"SpreadRow":{"type":"object","description":"Lightweight row — derived metrics only, no bids/asks JSONB.","required":["ts","position_id","condition_id"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}},"TokenOutcome":{"type":"object","description":"Token outcome (position)","required":["token_id","outcome"],"properties":{"token_id":{"type":"string"},"outcome":{"type":"string"}}},"TradeSide":{"type":"string","enum":["0","1"]},"TradeType":{"type":"string","enum":["0","1","2","3","4","5","6"]},"Trader":{"type":"object","description":"Trader profile info embedded in API responses\n\nCorresponds to SQL function: `pm_build_trader(address, name, pseudonym, profile_image, x_username, verified_badge)`\n\nUsed in:\n- holders endpoints (market/event holders)\n- trades endpoints\n- leaderboard endpoints","required":["address"],"properties":{"address":{"type":"string"},"name":{"type":["string","null"]},"pseudonym":{"type":["string","null"]},"profile_image":{"type":["string","null"]},"x_username":{"type":["string","null"]},"verified_badge":{"type":"boolean"}}},"TraderEventPnlEntry":{"type":"object","description":"Event-level PnL entry","properties":{"event_slug":{"type":["string","null"]},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"markets_traded":{"type":["integer","null"],"format":"int64"},"outcomes_traded":{"type":["integer","null"],"format":"int64"},"total_buys":{"type":["integer","null"],"format":"int64"},"total_sells":{"type":["integer","null"],"format":"int64"},"total_redemptions":{"type":["integer","null"],"format":"int64"},"total_merges":{"type":["integer","null"],"format":"int64"},"total_volume_usd":{"type":["number","null"],"format":"double"},"buy_usd":{"type":["number","null"],"format":"double"},"sell_usd":{"type":["number","null"],"format":"double"},"redemption_usd":{"type":["number","null"],"format":"double"},"merge_usd":{"type":["number","null"],"format":"double"},"realized_pnl_usd":{"type":["number","null"],"format":"double"},"winning_markets":{"type":["integer","null"],"format":"int64"},"losing_markets":{"type":["integer","null"],"format":"int64"},"total_fees":{"type":["number","null"],"format":"double"},"first_trade_at":{"type":["integer","null"],"format":"int64"},"last_trade_at":{"type":["integer","null"],"format":"int64"}}},"TraderInfo":{"type":"object","description":"Trader profile info - backwards compatibility","required":["address"],"properties":{"address":{"type":"string"},"name":{"type":["string","null"]},"pseudonym":{"type":["string","null"]},"profile_image":{"type":["string","null"]},"x_username":{"type":["string","null"]},"verified_badge":{"type":"boolean"}}},"TraderMarketPnlEntry":{"type":"object","description":"Market-level PnL entry","properties":{"condition_id":{"type":["string","null"]},"event_slug":{"type":["string","null"]},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"outcomes_traded":{"type":["integer","null"],"format":"int64"},"total_buys":{"type":["integer","null"],"format":"int64"},"total_sells":{"type":["integer","null"],"format":"int64"},"total_redemptions":{"type":["integer","null"],"format":"int64"},"total_merges":{"type":["integer","null"],"format":"int64"},"buy_usd":{"type":["number","null"],"format":"double"},"sell_usd":{"type":["number","null"],"format":"double"},"redemption_usd":{"type":["number","null"],"format":"double"},"merge_usd":{"type":["number","null"],"format":"double"},"realized_pnl_usd":{"type":["number","null"],"format":"double"},"winning_outcomes":{"type":["integer","null"],"format":"int64"},"total_fees":{"type":["number","null"],"format":"double"},"first_trade_at":{"type":["integer","null"],"format":"int64"},"last_trade_at":{"type":["integer","null"],"format":"int64"}}},"TraderOutcomePnlEntry":{"type":"object","description":"Outcome-level PnL entry (per outcome token / position_id)","properties":{"position_id":{"type":["string","null"]},"condition_id":{"type":["string","null"]},"market_slug":{"type":["string","null"]},"event_slug":{"type":["string","null"]},"title":{"type":["string","null"]},"image_url":{"type":["string","null"]},"outcome":{"type":["string","null"]},"outcome_index":{"type":["integer","null"],"format":"int32"},"won":{"type":["boolean","null"],"description":"TRUE = won, FALSE = lost, NULL = open or sold before resolution"},"total_buys":{"type":["integer","null"],"format":"int64"},"total_sells":{"type":["integer","null"],"format":"int64"},"total_shares_bought":{"type":["number","null"],"format":"double"},"total_shares_sold":{"type":["number","null"],"format":"double"},"total_buy_usd":{"type":["number","null"],"format":"double"},"total_sell_usd":{"type":["number","null"],"format":"double"},"redemption_usd":{"type":["number","null"],"format":"double","description":"Payout on redemption (non-zero only if won)"},"avg_entry_price":{"type":["number","null"],"format":"double","description":"VWAP price paid per share across all buys (0–1)"},"avg_exit_price":{"type":["number","null"],"format":"double","description":"VWAP price received per share across all sells (0–1)"},"realized_pnl_usd":{"type":["number","null"],"format":"double"},"total_fees":{"type":["number","null"],"format":"double"},"first_trade_at":{"type":["integer","null"],"format":"int64"},"last_trade_at":{"type":["integer","null"],"format":"int64"},"current_price":{"type":["number","null"],"format":"double","description":"Last traded price for this outcome (0–1). NULL if market_outcomes has no price yet."},"current_shares_balance":{"type":["number","null"],"format":"double","description":"Current shares held: balance / 1e6."},"current_value":{"type":["number","null"],"format":"double","description":"Estimated current USD value of held shares: (balance / 1e6) * current_price.\nOnly meaningful for open positions (balance > 0)."},"realized_pnl_pct":{"type":["number","null"],"format":"double","description":"Realized PnL as a percentage of total spend: (realized_pnl_usd / total_buy_usd) * 100.\nNULL when total_buy_usd = 0."}}},"TraderPnlSummary":{"type":"object","description":"Trader's global PnL summary (single trader)","properties":{"trader":{"type":["string","null"]},"realized_pnl_usd":{"type":["number","null"],"format":"double"},"events_traded":{"type":["integer","null"],"format":"int64"},"markets_traded":{"type":["integer","null"],"format":"int64"},"total_buys":{"type":["integer","null"],"format":"int64"},"total_sells":{"type":["integer","null"],"format":"int64"},"total_redemptions":{"type":["integer","null"],"format":"int64"},"total_merges":{"type":["integer","null"],"format":"int64"},"total_volume_usd":{"type":["number","null"],"format":"double"},"buy_volume_usd":{"type":["number","null"],"format":"double"},"sell_volume_usd":{"type":["number","null"],"format":"double"},"redemption_volume_usd":{"type":["number","null"],"format":"double"},"merge_volume_usd":{"type":["number","null"],"format":"double"},"markets_won":{"type":["integer","null"],"format":"int64"},"markets_lost":{"type":["integer","null"],"format":"int64"},"market_win_rate_pct":{"type":["number","null"],"format":"double"},"avg_pnl_per_market":{"type":["number","null"],"format":"double"},"avg_pnl_per_trade":{"type":["number","null"],"format":"double"},"avg_hold_time_seconds":{"type":["number","null"],"format":"double"},"total_fees":{"type":["number","null"],"format":"double"},"best_trade_pnl_usd":{"type":["number","null"],"format":"double"},"best_trade_condition_id":{"type":["string","null"]},"first_trade_at":{"type":["integer","null"],"format":"int64"},"last_trade_at":{"type":["integer","null"],"format":"int64"}}},"TraderVolumeChartResponse":{"type":"object","required":["volumes","has_more"],"properties":{"volumes":{"type":"array","items":{"$ref":"#/components/schemas/TraderVolumeDataPoint"}},"has_more":{"type":"boolean"}}},"TraderVolumeDataPoint":{"type":"object","required":["t","v","bv","sv","tc","btc","stc"],"properties":{"t":{"type":"integer","format":"int64"},"v":{"type":"number","format":"double"},"bv":{"type":"number","format":"double"},"sv":{"type":"number","format":"double"},"tc":{"type":"integer","format":"int32"},"btc":{"type":"integer","format":"int32"},"stc":{"type":"integer","format":"int32"}}},"TraderWithPnl":{"allOf":[{"$ref":"#/components/schemas/Trader"},{"type":"object","properties":{"pnl":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/TraderPnlSummary"}]}}}]},"WebhookAssetSymbol":{"type":"string","description":"Crypto asset symbols accepted by `asset_price_tick` and `asset_price_window_update` filters.","enum":["BTC","ETH","SOL","XRP","DOGE","BNB","HYPE"]},"WebhookTimeframe":{"type":"string","description":"Timeframe values accepted by webhook metric, milestone, spike, and asset-price filters.","enum":["1m","5m","15m","30m","1h","4h","6h","1d","24h","7d","30d"]}}}} \ No newline at end of file diff --git a/openapi/webhooks.json b/openapi/webhooks.json index 8619e61..60e66f0 100644 --- a/openapi/webhooks.json +++ b/openapi/webhooks.json @@ -4365,6 +4365,18 @@ "CloseToBondFilters": { "type": "object", "description": "Subscription filters for the `close_to_bond` event. At least one of `min_probability` or `max_probability` is required.", + "anyOf": [ + { + "required": [ + "min_probability" + ] + }, + { + "required": [ + "max_probability" + ] + } + ], "properties": { "min_probability": { "type": "number", diff --git a/openapi/ws.json b/openapi/ws.json index c66c23a..4fffd54 100644 --- a/openapi/ws.json +++ b/openapi/ws.json @@ -10,7 +10,13 @@ "host": "api.struct.to", "pathname": "/ws", "protocol": "wss", - "description": "Production WebSocket endpoint" + "description": "Production WebSocket endpoint (room-based subscriptions)" + }, + "alerts": { + "host": "api.struct.to", + "pathname": "/v1/ws/alerts", + "protocol": "wss", + "description": "WebSocket alerts endpoint — ephemeral real-time alert subscriptions. Pass API key via ?api-key= query parameter. Subscribe/unsubscribe by sending JSON messages. Subscriptions are ephemeral and end on disconnect." } }, "channels": { @@ -18,11 +24,14 @@ "address": "polymarket_trades", "title": "Trades", "summary": "Trades stream", - "description": "Real-time stream of matched Polymarket prediction-market trades. At least one filter is required — open-ended subscriptions are rejected to prevent fan-out across all trades.\n\n**Filters (at least one required):**\n- `condition_ids` — 64-char hex condition IDs (with or without `0x` prefix)\n- `market_slugs` — market slugs\n- `event_slugs` — event slugs (delivers all markets under each event)\n- `position_ids` — ERC-1155 token IDs (decimal or hex)\n\n**Unsubscribe:** Send `action: \"unsubscribe_all\"` to clear all subscriptions.", + "description": "Real-time stream of matched Polymarket prediction-market trades. At least one filter is required — open-ended subscriptions are rejected to prevent fan-out across all trades.\n\n**Filters (at least one required):**\n- `condition_ids` — 64-char hex condition IDs (with or without `0x` prefix)\n- `market_slugs` — market slugs\n- `event_slugs` — event slugs (delivers all markets under each event)\n- `position_ids` — ERC-1155 token IDs (decimal or hex)\n- `trade_types` — optional allowlist of trade types (e.g. `[\"OrderFilled\", \"OrdersMatched\"]`). Omit or pass `[]` for all types.\n\n**Unsubscribe:** Send `action: \"unsubscribe_all\"` to clear all subscriptions.", "messages": { "subscribe": { "$ref": "#/components/messages/TradesStreamSubscribe" }, + "subscribeResponse": { + "$ref": "#/components/messages/TradesStreamSubscribeResponse" + }, "tradeStreamEvent": { "$ref": "#/components/messages/TradeStreamEvent" } @@ -37,6 +46,9 @@ "subscribe": { "$ref": "#/components/messages/AssetPricesSubscribe" }, + "subscribeResponse": { + "$ref": "#/components/messages/AssetPricesSubscribeResponse" + }, "assetPriceTickEvent": { "$ref": "#/components/messages/AssetPriceTickEvent" }, @@ -54,6 +66,9 @@ "subscribe": { "$ref": "#/components/messages/AssetWindowUpdatesSubscribe" }, + "subscribeResponse": { + "$ref": "#/components/messages/AssetWindowUpdatesSubscribeResponse" + }, "assetWindowUpdateEvent": { "$ref": "#/components/messages/AssetWindowUpdateEvent" } @@ -68,6 +83,9 @@ "subscribe": { "$ref": "#/components/messages/MarketMetricsSubscribe" }, + "subscribeResponse": { + "$ref": "#/components/messages/MarketMetricsSubscribeResponse" + }, "marketMetricsEvent": { "$ref": "#/components/messages/MarketMetricsEvent" } @@ -82,6 +100,9 @@ "subscribe": { "$ref": "#/components/messages/EventMetricsSubscribe" }, + "subscribeResponse": { + "$ref": "#/components/messages/EventMetricsSubscribeResponse" + }, "eventMetricsEvent": { "$ref": "#/components/messages/EventMetricsEvent" } @@ -96,6 +117,9 @@ "subscribe": { "$ref": "#/components/messages/PositionMetricsSubscribe" }, + "subscribeResponse": { + "$ref": "#/components/messages/PositionMetricsSubscribeResponse" + }, "positionMetricsEvent": { "$ref": "#/components/messages/PositionMetricsEvent" } @@ -110,6 +134,9 @@ "subscribe": { "$ref": "#/components/messages/TraderPnlSubscribe" }, + "subscribeResponse": { + "$ref": "#/components/messages/TraderPnlSubscribeResponse" + }, "traderGlobalPnlEvent": { "$ref": "#/components/messages/TraderGlobalPnlEvent" }, @@ -130,6 +157,9 @@ "subscribe": { "$ref": "#/components/messages/TraderPositionsSubscribe" }, + "subscribeResponse": { + "$ref": "#/components/messages/TraderPositionsSubscribeResponse" + }, "traderPositionUpdateEvent": { "$ref": "#/components/messages/TraderPositionUpdateEvent" } @@ -144,6 +174,9 @@ "subscribe": { "$ref": "#/components/messages/AccountsSubscribe" }, + "subscribeResponse": { + "$ref": "#/components/messages/AccountsSubscribeResponse" + }, "accountsUpdateEvent": { "$ref": "#/components/messages/AccountsUpdateEvent" }, @@ -164,11 +197,31 @@ "subscribe": { "$ref": "#/components/messages/OrderBookSubscribe" }, + "subscribeResponse": { + "$ref": "#/components/messages/OrderBookSubscribeResponse" + }, "orderBookUpdateEvent": { "$ref": "#/components/messages/OrderBookUpdateEvent" } } }, + "polymarket_clob_rewards": { + "address": "polymarket_clob_rewards", + "title": "CLOB Rewards", + "summary": "CLOB reward configuration changes stream", + "description": "Real-time stream of Polymarket CLOB reward configuration changes. Emits events when rewards are added to a market, removed, or updated (e.g. rate changes, sponsor count changes, spread/size threshold changes).\n\n**Filters (optional):**\n- `condition_ids` — 64-char hex condition IDs to watch for reward changes\n- `subscribe_all` — set to `true` to receive ALL reward changes across all markets\n\nIf neither is provided, no events are delivered.\n\n**Event types:**\n- `added` — new reward configuration appeared on a market\n- `removed` — reward configuration removed from a market\n- `updated` — reward parameters changed (rate, spread, size, sponsors, etc.)\n\n**Unsubscribe:** Send `action: \"unsubscribe_all\"`.", + "messages": { + "subscribe": { + "$ref": "#/components/messages/ClobRewardsSubscribe" + }, + "subscribeResponse": { + "$ref": "#/components/messages/ClobRewardsSubscribeResponse" + }, + "clobRewardsUpdateEvent": { + "$ref": "#/components/messages/ClobRewardsUpdateEvent" + } + } + }, "polymarket_wallet_tracking": { "address": "polymarket_wallet_tracking", "title": "Wallet Tracking", @@ -178,10 +231,44 @@ "subscribe": { "$ref": "#/components/messages/WalletTrackingSubscribe" }, + "subscribeResponse": { + "$ref": "#/components/messages/WalletTrackingSubscribeResponse" + }, "walletTrackingAlertEvent": { "$ref": "#/components/messages/WalletTrackingAlertEvent" } } + }, + "ws_alerts": { + "address": "/v1/ws/alerts", + "title": "WebSocket Alerts", + "summary": "Ephemeral real-time alert subscriptions over WebSocket", + "description": "Connect to `wss://api.struct.to/v1/ws/alerts?api-key=`. Subscribe to webhook-style alert events by sending JSON messages. Subscriptions are ephemeral and end when the connection closes. The alerts WS path shares the same event/filter pipeline as HTTP webhooks; only delivery transport differs. Credits cost matches the corresponding webhook event.\n\n**Supported events:** trader_first_trade, trader_new_market, trader_whale_trade, trader_new_trade, trader_global_pnl, trader_market_pnl, trader_event_pnl, condition_metrics, event_metrics, position_metrics, market_volume_milestone, event_volume_milestone, position_volume_milestone, probability_spike, price_spike, market_volume_spike, event_volume_spike, position_volume_spike, close_to_bond, market_created, asset_price_tick, asset_price_window_update\n\nEach subscribe/unsubscribe request is typed per event and reuses the matching webhook filter schema. Server acknowledgements use `{\"op\":\"subscribed\"|\"unsubscribed\", ...}`, and pushed alert events use `{\"event\":\"...\",\"timestamp\":...,\"data\": ...}`.", + "servers": [ + { + "$ref": "#/servers/alerts" + } + ], + "messages": { + "subscribe": { + "$ref": "#/components/messages/WsAlertSubscribe" + }, + "unsubscribe": { + "$ref": "#/components/messages/WsAlertUnsubscribe" + }, + "subscribed": { + "$ref": "#/components/messages/WsAlertSubscribed" + }, + "unsubscribed": { + "$ref": "#/components/messages/WsAlertUnsubscribed" + }, + "error": { + "$ref": "#/components/messages/WsAlertError" + }, + "alertEvent": { + "$ref": "#/components/messages/WsAlertEvent" + } + } } }, "operations": { @@ -204,6 +291,9 @@ }, "summary": "Receive trades stream events", "messages": [ + { + "$ref": "#/channels/polymarket_trades/messages/subscribeResponse" + }, { "$ref": "#/channels/polymarket_trades/messages/tradeStreamEvent" } @@ -228,6 +318,9 @@ }, "summary": "Receive asset prices stream events", "messages": [ + { + "$ref": "#/channels/polymarket_asset_prices/messages/subscribeResponse" + }, { "$ref": "#/channels/polymarket_asset_prices/messages/assetPriceTickEvent" }, @@ -255,6 +348,9 @@ }, "summary": "Receive asset window updates stream events", "messages": [ + { + "$ref": "#/channels/polymarket_asset_window_updates/messages/subscribeResponse" + }, { "$ref": "#/channels/polymarket_asset_window_updates/messages/assetWindowUpdateEvent" } @@ -279,6 +375,9 @@ }, "summary": "Receive market (condition) metrics stream events", "messages": [ + { + "$ref": "#/channels/polymarket_market_metrics/messages/subscribeResponse" + }, { "$ref": "#/channels/polymarket_market_metrics/messages/marketMetricsEvent" } @@ -303,6 +402,9 @@ }, "summary": "Receive event metrics stream events", "messages": [ + { + "$ref": "#/channels/polymarket_event_metrics/messages/subscribeResponse" + }, { "$ref": "#/channels/polymarket_event_metrics/messages/eventMetricsEvent" } @@ -327,6 +429,9 @@ }, "summary": "Receive position (outcome token) metrics stream events", "messages": [ + { + "$ref": "#/channels/polymarket_position_metrics/messages/subscribeResponse" + }, { "$ref": "#/channels/polymarket_position_metrics/messages/positionMetricsEvent" } @@ -351,6 +456,9 @@ }, "summary": "Receive trader pnl stream events", "messages": [ + { + "$ref": "#/channels/polymarket_trader_pnl/messages/subscribeResponse" + }, { "$ref": "#/channels/polymarket_trader_pnl/messages/traderGlobalPnlEvent" }, @@ -381,6 +489,9 @@ }, "summary": "Receive trader position updates stream events", "messages": [ + { + "$ref": "#/channels/polymarket_trader_positions/messages/subscribeResponse" + }, { "$ref": "#/channels/polymarket_trader_positions/messages/traderPositionUpdateEvent" } @@ -405,6 +516,9 @@ }, "summary": "Receive account balances stream events", "messages": [ + { + "$ref": "#/channels/polymarket_accounts/messages/subscribeResponse" + }, { "$ref": "#/channels/polymarket_accounts/messages/accountsUpdateEvent" }, @@ -435,11 +549,41 @@ }, "summary": "Receive order book snapshots stream events", "messages": [ + { + "$ref": "#/channels/polymarket_order_book/messages/subscribeResponse" + }, { "$ref": "#/channels/polymarket_order_book/messages/orderBookUpdateEvent" } ] }, + "subscribePolymarketClobRewards": { + "action": "send", + "channel": { + "$ref": "#/channels/polymarket_clob_rewards" + }, + "summary": "Subscribe to clob reward configuration changes stream", + "messages": [ + { + "$ref": "#/channels/polymarket_clob_rewards/messages/subscribe" + } + ] + }, + "receivePolymarketClobRewards": { + "action": "receive", + "channel": { + "$ref": "#/channels/polymarket_clob_rewards" + }, + "summary": "Receive clob reward configuration changes stream events", + "messages": [ + { + "$ref": "#/channels/polymarket_clob_rewards/messages/subscribeResponse" + }, + { + "$ref": "#/channels/polymarket_clob_rewards/messages/clobRewardsUpdateEvent" + } + ] + }, "subscribePolymarketWalletTracking": { "action": "send", "channel": { @@ -459,10 +603,49 @@ }, "summary": "Receive wallet trade tracking stream events", "messages": [ + { + "$ref": "#/channels/polymarket_wallet_tracking/messages/subscribeResponse" + }, { "$ref": "#/channels/polymarket_wallet_tracking/messages/walletTrackingAlertEvent" } ] + }, + "subscribeWsAlerts": { + "action": "send", + "channel": { + "$ref": "#/channels/ws_alerts" + }, + "summary": "Subscribe or unsubscribe to alert events", + "messages": [ + { + "$ref": "#/channels/ws_alerts/messages/subscribe" + }, + { + "$ref": "#/channels/ws_alerts/messages/unsubscribe" + } + ] + }, + "receiveWsAlerts": { + "action": "receive", + "channel": { + "$ref": "#/channels/ws_alerts" + }, + "summary": "Receive typed alert events and subscription acknowledgements", + "messages": [ + { + "$ref": "#/channels/ws_alerts/messages/subscribed" + }, + { + "$ref": "#/channels/ws_alerts/messages/unsubscribed" + }, + { + "$ref": "#/channels/ws_alerts/messages/error" + }, + { + "$ref": "#/channels/ws_alerts/messages/alertEvent" + } + ] } }, "components": { @@ -479,6 +662,12 @@ "$ref": "#/components/schemas/TradeStreamEvent" } }, + "TradesStreamSubscribeResponse": { + "summary": "Subscription acknowledgement for trades stream", + "payload": { + "$ref": "#/components/schemas/TradesStreamSubscribeResponse" + } + }, "AssetPricesSubscribe": { "summary": "Subscribe to asset prices stream", "payload": { @@ -497,6 +686,12 @@ "$ref": "#/components/schemas/AssetPriceWindowUpdateEvent" } }, + "AssetPricesSubscribeResponse": { + "summary": "Subscription acknowledgement for asset prices stream", + "payload": { + "$ref": "#/components/schemas/AssetPricesSubscribeResponse" + } + }, "AssetWindowUpdatesSubscribe": { "summary": "Subscribe to asset window updates stream", "payload": { @@ -509,6 +704,12 @@ "$ref": "#/components/schemas/AssetWindowUpdateEvent" } }, + "AssetWindowUpdatesSubscribeResponse": { + "summary": "Subscription acknowledgement for asset window updates stream", + "payload": { + "$ref": "#/components/schemas/AssetWindowUpdatesSubscribeResponse" + } + }, "MarketMetricsSubscribe": { "summary": "Subscribe to market (condition) metrics stream", "payload": { @@ -521,6 +722,12 @@ "$ref": "#/components/schemas/MarketMetricsEvent" } }, + "MarketMetricsSubscribeResponse": { + "summary": "Subscription acknowledgement for market (condition) metrics stream", + "payload": { + "$ref": "#/components/schemas/MarketMetricsSubscribeResponse" + } + }, "EventMetricsSubscribe": { "summary": "Subscribe to event metrics stream", "payload": { @@ -533,6 +740,12 @@ "$ref": "#/components/schemas/EventMetricsEvent" } }, + "EventMetricsSubscribeResponse": { + "summary": "Subscription acknowledgement for event metrics stream", + "payload": { + "$ref": "#/components/schemas/EventMetricsSubscribeResponse" + } + }, "PositionMetricsSubscribe": { "summary": "Subscribe to position (outcome token) metrics stream", "payload": { @@ -545,6 +758,12 @@ "$ref": "#/components/schemas/PositionMetricsEvent" } }, + "PositionMetricsSubscribeResponse": { + "summary": "Subscription acknowledgement for position (outcome token) metrics stream", + "payload": { + "$ref": "#/components/schemas/PositionMetricsSubscribeResponse" + } + }, "TraderPnlSubscribe": { "summary": "Subscribe to trader pnl stream", "payload": { @@ -569,6 +788,12 @@ "$ref": "#/components/schemas/TraderEventPnlEvent" } }, + "TraderPnlSubscribeResponse": { + "summary": "Subscription acknowledgement for trader pnl stream", + "payload": { + "$ref": "#/components/schemas/TraderPnlSubscribeResponse" + } + }, "TraderPositionsSubscribe": { "summary": "Subscribe to trader position updates stream", "payload": { @@ -581,6 +806,12 @@ "$ref": "#/components/schemas/TraderPositionUpdateEvent" } }, + "TraderPositionsSubscribeResponse": { + "summary": "Subscription acknowledgement for trader position updates stream", + "payload": { + "$ref": "#/components/schemas/TraderPositionsSubscribeResponse" + } + }, "AccountsSubscribe": { "summary": "Subscribe to account balances stream", "payload": { @@ -605,6 +836,12 @@ "$ref": "#/components/schemas/MaticUpdateEvent" } }, + "AccountsSubscribeResponse": { + "summary": "Subscription acknowledgement for account balances stream", + "payload": { + "$ref": "#/components/schemas/AccountsSubscribeResponse" + } + }, "OrderBookSubscribe": { "summary": "Subscribe to order book snapshots stream", "payload": { @@ -617,6 +854,30 @@ "$ref": "#/components/schemas/OrderBookUpdateEvent" } }, + "OrderBookSubscribeResponse": { + "summary": "Subscription acknowledgement for order book snapshots stream", + "payload": { + "$ref": "#/components/schemas/OrderBookSubscribeResponse" + } + }, + "ClobRewardsSubscribe": { + "summary": "Subscribe to clob reward configuration changes stream", + "payload": { + "$ref": "#/components/schemas/ClobRewardsSubscribeMessage" + } + }, + "ClobRewardsUpdateEvent": { + "summary": "Server-pushed CLOB reward change event", + "payload": { + "$ref": "#/components/schemas/ClobRewardsUpdateEvent" + } + }, + "ClobRewardsSubscribeResponse": { + "summary": "Subscription acknowledgement for clob reward configuration changes stream", + "payload": { + "$ref": "#/components/schemas/ClobRewardsSubscribeResponse" + } + }, "WalletTrackingSubscribe": { "summary": "Subscribe to wallet trade tracking stream", "payload": { @@ -628,258 +889,282 @@ "payload": { "$ref": "#/components/schemas/WalletTrackingAlertEvent" } + }, + "WalletTrackingSubscribeResponse": { + "summary": "Subscription acknowledgement for wallet trade tracking stream", + "payload": { + "$ref": "#/components/schemas/WalletTrackingSubscribeResponse" + } + }, + "WsAlertSubscribe": { + "summary": "Subscribe to an alert event type", + "payload": { + "$ref": "#/components/schemas/WsAlertSubscribeMessage" + } + }, + "WsAlertUnsubscribe": { + "summary": "Unsubscribe from an alert event type", + "payload": { + "$ref": "#/components/schemas/WsAlertUnsubscribeMessage" + } + }, + "WsAlertSubscribed": { + "summary": "Alert subscription acknowledgement", + "payload": { + "$ref": "#/components/schemas/WsAlertSubscribedResponse" + } + }, + "WsAlertUnsubscribed": { + "summary": "Alert unsubscription acknowledgement", + "payload": { + "$ref": "#/components/schemas/WsAlertUnsubscribedResponse" + } + }, + "WsAlertError": { + "summary": "Alerts WebSocket error response", + "payload": { + "$ref": "#/components/schemas/WsAlertErrorResponse" + } + }, + "WsAlertEvent": { + "summary": "Typed alert event pushed from server", + "payload": { + "$ref": "#/components/schemas/WsAlertEventPayload" + } } }, "schemas": { - "WalletTrackingAlertEvent": { + "AssetPriceWindowUpdateFilters": { "type": "object", - "description": "Server-pushed event: a trade executed by a tracked wallet. Envelope type: \"wallet_tracking_alert\".", - "required": [ - "is_buy", - "trader", - "position_id", - "usd_amount", - "shares_amount", - "price", - "confirmed_at" - ], + "description": "Subscription filters for the `asset_price_window_update` event. All fields are optional.", "properties": { - "is_buy": { - "type": "boolean", - "description": "True = buy, false = sell" - }, - "trader": { - "type": "string", - "description": "Trader EVM wallet address (lowercase)" - }, - "condition_id": { - "type": [ - "string", - "null" - ], - "description": "64-char hex condition ID" - }, - "position_id": { - "type": "string", - "description": "ERC-1155 outcome token ID (decimal string)" - }, - "usd_amount": { - "type": "string", - "description": "USD value of the trade (decimal string, 6dp)" - }, - "shares_amount": { - "type": "string", - "description": "Number of shares traded (decimal string, 6dp)" - }, - "price": { - "type": "number", - "minimum": 0.0, - "maximum": 1.0, - "description": "Trade price (0–1)" - }, - "probability": { - "type": [ - "number", - "null" - ], - "description": "Implied probability (0–1)" - }, - "metadata": { - "oneOf": [ - { - "$ref": "#/components/schemas/PredictionMarketMetadata" - }, - { - "type": "null" - } - ], - "description": "Market metadata — null when enrichment is unavailable" + "asset_symbols": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "BTC", + "ETH", + "SOL", + "XRP", + "DOGE", + "BNB", + "HYPE" + ] + }, + "maxItems": 500, + "description": "Restrict to these crypto assets. Empty = all assets." }, - "confirmed_at": { - "type": "integer", - "format": "int64", - "description": "Unix seconds" + "timeframes": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "5m", + "15m", + "1h", + "4h", + "1d", + "24h" + ] + }, + "maxItems": 500, + "description": "Restrict to these candle sizes. Empty = all sizes." } } }, - "PredictionMarketMetadata": { + "AssetPriceTickFilters": { "type": "object", - "description": "Market metadata enrichment attached to wallet tracking alerts", + "description": "Subscription filters for the `asset_price_tick` event. All fields are optional.", "properties": { - "slug": { - "type": [ - "string", - "null" - ], - "description": "Market slug" - }, - "question": { - "type": [ - "string", - "null" - ], - "description": "Market question text" - }, - "outcome": { - "type": [ - "string", - "null" - ], - "description": "Outcome name (e.g. \"Yes\")" - }, - "outcome_index": { - "type": [ - "integer", - "null" - ] - }, - "image_url": { - "type": [ - "string", - "null" - ] + "asset_symbols": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "BTC", + "ETH", + "SOL", + "XRP", + "DOGE", + "BNB", + "HYPE" + ] + }, + "description": "Restrict to these crypto assets. Empty = all assets." } } }, - "OrderBookUpdateEvent": { + "MarketCreatedFilters": { "type": "object", - "description": "Server-pushed event: full CLOB orderbook snapshot for an outcome token. Envelope type: \"order_book_update\". Delivered whenever the book changes for a subscribed condition or position.", - "required": [ - "asset_id", - "market", - "bids", - "asks", - "timestamp", - "hash" - ], + "description": "Subscription filters for the `market_created` event. All fields are optional.", "properties": { - "asset_id": { - "type": "string", - "description": "Hex token ID (position / outcome token)" - }, - "market": { - "type": "string", - "description": "Condition ID (hex)" - }, - "bids": { + "tags": { "type": "array", "items": { - "$ref": "#/components/schemas/OrderBookLevel" + "type": "string" }, - "description": "Bid levels sorted best-first (highest price first)" + "maxItems": 500, + "description": "Restrict to markets with these tags or category names (case-insensitive match)." }, - "asks": { + "condition_ids": { "type": "array", "items": { - "$ref": "#/components/schemas/OrderBookLevel" + "type": "string" }, - "description": "Ask levels sorted best-first (lowest price first)" + "maxItems": 500, + "description": "Restrict to these specific markets." }, - "timestamp": { - "type": "integer", - "format": "int64", - "description": "Unix milliseconds from CLOB message" + "event_slugs": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to markets belonging to these events." }, - "hash": { - "type": "string", - "description": "Orderbook content hash — identical hash means no change" + "exclude_shortterm_markets": { + "type": "boolean", + "description": "When `true`, suppress webhooks for short-term \"updown\" markets (event slugs containing `updown`). Default: `false`." + } + } + }, + "CloseToBondFilters": { + "type": "object", + "description": "Subscription filters for the `close_to_bond` event. At least one of `min_probability` or `max_probability` is required.", + "anyOf": [ + { + "required": [ + "min_probability" + ] }, - "best_bid": { - "type": [ - "number", - "null" - ], - "description": "Best bid price (0–1)" + { + "required": [ + "max_probability" + ] + } + ], + "properties": { + "min_probability": { + "type": "number", + "minimum": 0.0, + "maximum": 1.0, + "description": "Trigger when the YES outcome price is ≥ this value (e.g. 0.95 for 95% certainty). At least one of `min_probability` or `max_probability` must be set." }, - "best_ask": { - "type": [ - "number", - "null" - ], - "description": "Best ask price (0–1)" + "max_probability": { + "type": "number", + "minimum": 0.0, + "maximum": 1.0, + "description": "Trigger when the YES outcome price is ≤ this value (e.g. 0.05 for near-certain NO)." }, - "mid_price": { - "type": [ - "number", - "null" - ], - "description": "(best_bid + best_ask) / 2" + "condition_ids": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to these markets." }, - "spread": { - "type": [ - "number", - "null" - ], - "description": "best_ask − best_bid" + "position_ids": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to these outcome token IDs." }, - "bid_liquidity_usd": { - "type": [ - "number", - "null" - ], - "description": "Total USD value of all bid levels" + "event_slugs": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to markets in these events." }, - "ask_liquidity_usd": { - "type": [ - "number", - "null" - ], - "description": "Total USD value of all ask levels" + "outcomes": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to these outcome names (e.g. [\"Yes\", \"No\"])." }, - "bid_levels": { - "type": [ - "integer", - "null" - ], - "description": "Number of bid price levels" + "position_outcome_indices": { + "type": "array", + "items": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "maxItems": 500, + "description": "Restrict by outcome index. 0 = Yes/Up, 1 = No. Position 0 usually represents the Up/Yes side in binary markets." }, - "ask_levels": { - "type": [ - "integer", - "null" - ], - "description": "Number of ask price levels" + "exclude_shortterm_markets": { + "type": "boolean", + "description": "When `true`, suppress webhooks for short-term \"updown\" markets. Default: `false`." } } }, - "OrderBookLevel": { - "type": "array", - "description": "A single price level: [price_string, size_string]", - "items": { - "type": "string" - }, - "minItems": 2, - "maxItems": 2 - }, - "MaticUpdateEvent": { + "PositionVolumeSpikeFilters": { "type": "object", - "description": "Server-pushed event: MATIC native balance change for a wallet. Envelope type: \"matic_update\". Only delivered when `include_matic: true`.", + "description": "Subscription filters for the `position_volume_spike` event. `spike_ratio` is required.", "required": [ - "address", - "block_number", - "updated_at" + "spike_ratio" ], "properties": { - "address": { - "type": "string", - "description": "Wallet address (0x-prefixed hex)" + "spike_ratio": { + "type": "number", + "exclusiveMinimum": 1.0, + "description": "**Required.** Multiplier threshold (must be > 1.0). Fires when current volume >= snapshot × ratio." }, - "token_address": { - "type": "string", - "description": "Native token address — omitted when not available" + "window_secs": { + "type": "integer", + "minimum": 1, + "maximum": 600, + "description": "Force snapshot reset after this many seconds (max 600 / 10 minutes)." }, - "balance": { - "type": "string", - "description": "Current MATIC balance (decimal string) — omitted when not available" + "position_ids": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to these outcome token IDs." }, - "block_number": { - "type": "integer", - "format": "uint64" + "condition_ids": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to positions within these markets." }, - "updated_at": { - "type": "integer", - "format": "int64", - "description": "Unix seconds" + "outcomes": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to these outcome names." + }, + "timeframes": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "1m", + "5m", + "30m", + "1h", + "6h", + "1d", + "24h", + "7d", + "30d" + ] + }, + "maxItems": 500, + "description": "Restrict to these aggregation windows." } } }, @@ -924,6 +1209,22 @@ "type": "string" }, "description": "ERC-1155 outcome token IDs (decimal or hex strings)" + }, + "trade_types": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "OrderFilled", + "Redemption", + "Merge", + "Split", + "Cancelled", + "PositionsConverted", + "OrdersMatched" + ] + }, + "description": "Only receive trades of these types. Empty array = all types." } } }, @@ -955,54 +1256,199 @@ "type": "string" } }, + "trade_types": { + "type": "array", + "items": { + "type": "string" + } + }, "rejected": { "type": "array", "items": { "type": "string" }, - "description": "Filter values that were rejected (invalid format)" + "description": "Filter values that were rejected (invalid format or unknown trade type)" } } }, - "AssetPricesSubscribeMessage": { + "TradeStreamEvent": { "type": "object", - "description": "Subscribe to the asset prices stream. Empty asset_symbols = all assets.", + "description": "Server-pushed event: a matched trade on a subscribed market/position/event/slug. Envelope type: \"trade_stream_update\".", "required": [ - "action" + "id", + "trader", + "taker", + "position_id", + "hash", + "block", + "confirmed_at", + "usd_amount", + "shares_amount", + "fee", + "price" ], "properties": { - "action": { + "id": { "type": "string", - "enum": [ - "subscribe", - "unsubscribe_all" - ] + "description": "Trade ID" }, - "asset_symbols": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Uppercase asset symbols (e.g. \"BTC\", \"ETH\"). Empty = subscribe to all." - } - } - }, - "AssetPricesSubscribeResponse": { - "type": "object", - "description": "Server acknowledgement for an asset prices subscription", - "properties": { - "asset_symbols": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Accepted symbols. Empty array means subscribed to all symbols." + "hash": { + "type": "string", + "description": "Transaction hash (hex)" + }, + "chain_id": { + "type": "integer", + "format": "uint64" + }, + "block": { + "type": "integer", + "format": "uint64" + }, + "confirmed_at": { + "type": "integer", + "format": "uint64", + "description": "Unix seconds" + }, + "log_index": { + "type": "integer", + "format": "uint64" + }, + "block_index": { + "type": "integer", + "format": "uint64" + }, + "order_hash": { + "type": "string", + "description": "Order hash (hex)" + }, + "trader": { + "type": "string", + "description": "Limit-order maker wallet address" + }, + "taker": { + "type": "string", + "description": "Order taker wallet address" + }, + "side": { + "type": [ + "string", + "null" + ], + "description": "\"Buy\" or \"Sell\" (null for non-trade operations like Redemption, Merge, Split)" + }, + "condition_id": { + "type": [ + "string", + "null" + ], + "description": "64-char hex condition ID" + }, + "position_id": { + "type": "string", + "description": "ERC-1155 outcome token ID (decimal string)" + }, + "outcome": { + "type": [ + "string", + "null" + ], + "description": "Outcome name (e.g. \"Yes\")" + }, + "outcome_index": { + "type": [ + "integer", + "null" + ], + "description": "0 = Yes, 1 = No" + }, + "question": { + "type": [ + "string", + "null" + ] + }, + "slug": { + "type": [ + "string", + "null" + ], + "description": "Market slug" + }, + "event_slug": { + "type": [ + "string", + "null" + ] + }, + "usd_amount": { + "type": "string", + "description": "USD value of the trade (decimal string)" + }, + "shares_amount": { + "type": "string", + "description": "Number of shares traded (decimal string)" + }, + "price": { + "type": "number", + "minimum": 0.0, + "maximum": 1.0, + "description": "Trade price (0–1)" + }, + "probability": { + "type": [ + "number", + "null" + ], + "description": "Implied probability (0–1)" + }, + "fee": { + "type": "string", + "description": "Protocol fee paid (decimal string)" + }, + "exchange": { + "type": "string", + "description": "Exchange identifier" + }, + "trade_type": { + "type": "string", + "description": "\"OrderFilled\", \"Redemption\", \"Merge\", \"Split\", \"Cancelled\", \"PositionsConverted\", \"OrdersMatched\"" + }, + "winning_outcome_index": { + "type": [ + "integer", + "null" + ], + "description": "Resolved winning outcome index" + }, + "is_known_surebet": { + "type": "boolean" + }, + "is_coordinated": { + "type": "boolean" + }, + "is_surebet_trade": { + "type": "boolean" + }, + "surebet_price_sum": { + "type": [ + "number", + "null" + ] + }, + "is_bot": { + "type": "boolean" + }, + "bot_reason": { + "type": [ + "string", + "null" + ] } } }, - "AssetWindowUpdatesSubscribeMessage": { + "AssetPricesSubscribeMessage": { "type": "object", - "description": "Subscribe to the asset window updates stream. At least one of asset_symbols or timeframes must be non-empty.", + "description": "Subscribe to the asset prices stream. Empty asset_symbols = all assets.", "required": [ "action" ], @@ -1019,107 +1465,119 @@ "items": { "type": "string" }, - "description": "Uppercase asset symbols (e.g. \"BTC\", \"ETH\")" - }, - "timeframes": { - "type": "array", - "items": { - "type": "string", - "enum": [ - "5m", - "15m", - "1h", - "4h", - "1d", - "24h" - ] - }, - "description": "Candle sizes to filter by. \"1d\" and \"24h\" are treated as equivalent." + "description": "Uppercase asset symbols (e.g. \"BTC\", \"ETH\"). Empty = subscribe to all." } } }, - "AssetWindowUpdatesSubscribeResponse": { + "AssetPricesSubscribeResponse": { "type": "object", - "description": "Server acknowledgement for an asset window updates subscription", + "description": "Server acknowledgement for an asset prices subscription", "properties": { "asset_symbols": { "type": "array", "items": { "type": "string" - } - }, - "timeframes": { - "type": "array", - "items": { - "type": "string" - } - }, - "error": { - "type": [ - "string", - "null" - ], - "description": "Set if the subscription was rejected (e.g. no filters provided)" + }, + "description": "Accepted symbols. Empty array means subscribed to all symbols." } } }, - "MarketMetricsSubscribeMessage": { + "AssetPriceTickEvent": { "type": "object", - "description": "Subscribe to the market metrics stream. condition_ids is required and must be non-empty.", + "description": "Server-pushed event: a crypto-asset price tick. Envelope type: \"asset_price_tick\".", "required": [ - "action", - "condition_ids" + "event_type", + "symbol", + "price", + "timestamp_ms", + "published_at" ], "properties": { - "action": { + "event_type": { "type": "string", - "enum": [ - "subscribe", - "unsubscribe_all" - ] + "description": "Always \"asset_price_tick\"" }, - "condition_ids": { - "type": "array", - "items": { - "type": "string" - }, - "description": "64-char hex condition IDs (with or without 0x prefix)", - "minItems": 1 + "symbol": { + "type": "string", + "description": "Uppercase asset symbol (e.g. \"BTC\")" + }, + "price": { + "type": "number", + "description": "Current price in USD" + }, + "timestamp_ms": { + "type": "integer", + "format": "int64", + "description": "Event timestamp in Unix milliseconds" + }, + "published_at": { + "type": "integer", + "format": "int64", + "description": "Publish timestamp in Unix milliseconds" } } }, - "MarketMetricsSubscribeResponse": { + "AssetPriceWindowUpdateEvent": { "type": "object", - "description": "Server acknowledgement for a market metrics subscription", + "description": "Server-pushed event: candle open or close for a crypto asset. Envelope type: \"asset_price_window_update\". Delivered from both `polymarket_asset_prices` and `polymarket_asset_window_updates` rooms.", + "required": [ + "event_type", + "symbol", + "variant", + "start_time", + "end_time", + "open_price", + "close_price", + "update_type", + "published_at" + ], "properties": { - "condition_ids": { - "type": "array", - "items": { - "type": "string" - } + "event_type": { + "type": "string", + "description": "Always \"asset_price_window_update\"" }, - "rejected": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Condition IDs that were rejected (invalid format)" + "symbol": { + "type": "string", + "description": "Uppercase asset symbol (e.g. \"BTC\")" }, - "error": { - "type": [ - "string", - "null" - ], - "description": "Set if the entire subscription was rejected" + "variant": { + "type": "string", + "description": "Candle size / timeframe (e.g. \"5m\", \"1h\", \"1d\")" + }, + "start_time": { + "type": "integer", + "format": "int64", + "description": "Candle start in Unix milliseconds" + }, + "end_time": { + "type": "integer", + "format": "int64", + "description": "Candle end in Unix milliseconds" + }, + "open_price": { + "type": "number", + "description": "Candle open price in USD" + }, + "close_price": { + "type": "number", + "description": "Candle close price in USD" + }, + "update_type": { + "type": "string", + "description": "\"open\" = candle starting, \"close\" = candle finalised" + }, + "published_at": { + "type": "integer", + "format": "int64", + "description": "Publish timestamp in Unix milliseconds" } } }, - "EventMetricsSubscribeMessage": { + "AssetWindowUpdatesSubscribeMessage": { "type": "object", - "description": "Subscribe to the event metrics stream. event_slugs is required and must be non-empty.", + "description": "Subscribe to the asset window updates stream. At least one of asset_symbols or timeframes must be non-empty.", "required": [ - "action", - "event_slugs" + "action" ], "properties": { "action": { @@ -1129,27 +1587,41 @@ "unsubscribe_all" ] }, - "event_slugs": { + "asset_symbols": { "type": "array", "items": { "type": "string" }, - "description": "Event slugs (lowercase)", - "minItems": 1 + "description": "Uppercase asset symbols (e.g. \"BTC\", \"ETH\")" + }, + "timeframes": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "5m", + "15m", + "1h", + "4h", + "1d", + "24h" + ] + }, + "description": "Candle sizes to filter by. \"1d\" and \"24h\" are treated as equivalent." } } }, - "EventMetricsSubscribeResponse": { + "AssetWindowUpdatesSubscribeResponse": { "type": "object", - "description": "Server acknowledgement for an event metrics subscription", + "description": "Server acknowledgement for an asset window updates subscription", "properties": { - "event_slugs": { + "asset_symbols": { "type": "array", "items": { "type": "string" } }, - "rejected": { + "timeframes": { "type": "array", "items": { "type": "string" @@ -1159,16 +1631,25 @@ "type": [ "string", "null" - ] + ], + "description": "Set if the subscription was rejected (e.g. no filters provided)" } } }, - "PositionMetricsSubscribeMessage": { + "AssetWindowUpdateEvent": { + "allOf": [ + { + "$ref": "#/components/schemas/AssetPriceWindowUpdateEvent" + } + ], + "description": "Server-pushed event from the polymarket_asset_window_updates room. Same payload as AssetPriceWindowUpdateEvent. Envelope type: \"asset_price_window_update\"." + }, + "MarketMetricsSubscribeMessage": { "type": "object", - "description": "Subscribe to the position metrics stream. position_ids is required and must be non-empty.", + "description": "Subscribe to the market metrics stream. condition_ids is required and must be non-empty.", "required": [ "action", - "position_ids" + "condition_ids" ], "properties": { "action": { @@ -1178,21 +1659,21 @@ "unsubscribe_all" ] }, - "position_ids": { + "condition_ids": { "type": "array", "items": { "type": "string" }, - "description": "ERC-1155 outcome token IDs (decimal or hex strings)", + "description": "64-char hex condition IDs (with or without 0x prefix)", "minItems": 1 } } }, - "PositionMetricsSubscribeResponse": { + "MarketMetricsSubscribeResponse": { "type": "object", - "description": "Server acknowledgement for a position metrics subscription", + "description": "Server acknowledgement for a market metrics subscription", "properties": { - "position_ids": { + "condition_ids": { "type": "array", "items": { "type": "string" @@ -1202,71 +1683,97 @@ "type": "array", "items": { "type": "string" - } + }, + "description": "Condition IDs that were rejected (invalid format)" }, "error": { "type": [ "string", "null" - ] + ], + "description": "Set if the entire subscription was rejected" } } }, - "TraderPnlSubscribeMessage": { + "MarketMetricsEvent": { "type": "object", - "description": "Subscribe to the trader PnL stream. traders is required and must be non-empty.", + "description": "Server-pushed event: metrics update for one timeframe of a condition. Envelope type: \"market_metrics_update\". One event is emitted per timeframe window on each update.", "required": [ - "action", - "traders" + "condition_id", + "timeframe", + "usd_volume", + "fees", + "txns", + "unique_traders", + "historical_confirmed_at", + "latest_confirmed_at", + "latest_block" ], "properties": { - "action": { + "condition_id": { + "type": "string", + "description": "64-char hex condition ID" + }, + "timeframe": { "type": "string", "enum": [ - "subscribe", - "unsubscribe_all" + "1m", + "5m", + "30m", + "1h", + "6h", + "24h", + "7d", + "30d" ] }, - "traders": { - "type": "array", - "items": { - "type": "string" - }, - "description": "EVM wallet addresses", - "minItems": 1 - } - } - }, - "TraderPnlSubscribeResponse": { - "type": "object", - "description": "Server acknowledgement for a trader PnL subscription", - "properties": { - "traders": { - "type": "array", - "items": { - "type": "string" - } - }, - "rejected": { - "type": "array", - "items": { - "type": "string" - } - }, - "error": { + "timestamp": { "type": [ - "string", + "integer", "null" - ] + ], + "format": "int64", + "description": "Optional event timestamp (Unix seconds)" + }, + "usd_volume": { + "type": "string", + "description": "USD volume in this timeframe window (decimal string)" + }, + "fees": { + "type": "number", + "description": "Total fees in this window" + }, + "txns": { + "type": "integer", + "format": "int64", + "description": "Number of transactions" + }, + "unique_traders": { + "type": "integer", + "format": "int64" + }, + "historical_confirmed_at": { + "type": "integer", + "format": "int64", + "description": "Earliest trade timestamp in window (Unix seconds)" + }, + "latest_confirmed_at": { + "type": "integer", + "format": "int64", + "description": "Latest trade timestamp in window (Unix seconds)" + }, + "latest_block": { + "type": "integer", + "format": "int64" } } }, - "TraderPositionsSubscribeMessage": { + "EventMetricsSubscribeMessage": { "type": "object", - "description": "Subscribe to the trader positions stream. traders is required and must be non-empty.", + "description": "Subscribe to the event metrics stream. event_slugs is required and must be non-empty.", "required": [ "action", - "traders" + "event_slugs" ], "properties": { "action": { @@ -1276,21 +1783,21 @@ "unsubscribe_all" ] }, - "traders": { + "event_slugs": { "type": "array", "items": { "type": "string" }, - "description": "EVM wallet addresses", + "description": "Event slugs (lowercase)", "minItems": 1 } } }, - "TraderPositionsSubscribeResponse": { + "EventMetricsSubscribeResponse": { "type": "object", - "description": "Server acknowledgement for a trader positions subscription", + "description": "Server acknowledgement for an event metrics subscription", "properties": { - "traders": { + "event_slugs": { "type": "array", "items": { "type": "string" @@ -1310,77 +1817,80 @@ } } }, - "AccountsSubscribeMessage": { + "EventMetricsEvent": { "type": "object", - "description": "Subscribe to the accounts stream. `wallets` is required. Share balance updates (`accounts_update`) are always delivered. Set `include_usdce` or `include_matic` to also receive those balance streams.", + "description": "Server-pushed event: aggregated metrics update for one timeframe of an event. Envelope type: \"event_metrics_update\". One event is emitted per timeframe window on each update.", "required": [ - "action", - "wallets" - ], - "properties": { - "action": { - "type": "string", - "enum": [ - "subscribe", - "unsubscribe_all" + "event_slug", + "timeframe", + "usd_volume", + "fees", + "txns", + "unique_traders", + "historical_confirmed_at", + "latest_confirmed_at", + "latest_block" + ], + "properties": { + "event_slug": { + "type": "string" + }, + "timeframe": { + "type": "string", + "enum": [ + "1m", + "5m", + "30m", + "1h", + "6h", + "24h", + "7d", + "30d" ] }, - "wallets": { - "type": "array", - "items": { - "type": "string" - }, - "description": "EVM wallet addresses", - "minItems": 1 + "timestamp": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Optional event timestamp (Unix seconds)" }, - "include_usdce": { - "type": "boolean", - "default": false, - "description": "Also stream USDCe collateral balance updates for subscribed wallets" + "usd_volume": { + "type": "string", + "description": "USD volume in this timeframe window (decimal string)" }, - "include_matic": { - "type": "boolean", - "default": false, - "description": "Also stream MATIC gas balance updates for subscribed wallets" - } - } - }, - "AccountsSubscribeResponse": { - "type": "object", - "description": "Server acknowledgement for an accounts subscription", - "properties": { - "wallets": { - "type": "array", - "items": { - "type": "string" - } + "fees": { + "type": "number" }, - "rejected": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Addresses rejected (invalid format)" + "txns": { + "type": "integer", + "format": "int64" }, - "include_usdce": { - "type": "boolean" + "unique_traders": { + "type": "integer", + "format": "int64" }, - "include_matic": { - "type": "boolean" + "historical_confirmed_at": { + "type": "integer", + "format": "int64" }, - "error": { - "type": [ - "string", - "null" - ] + "latest_confirmed_at": { + "type": "integer", + "format": "int64" + }, + "latest_block": { + "type": "integer", + "format": "int64" } } }, - "OrderBookSubscribeMessage": { + "PositionMetricsSubscribeMessage": { "type": "object", - "description": "Subscribe to the order book stream. At least one filter is required. Maximum 500 combined condition_ids + position_ids per client. No `type` field is needed — the server routes by room_id.", + "description": "Subscribe to the position metrics stream. position_ids is required and must be non-empty.", "required": [ - "action" + "action", + "position_ids" ], "properties": { "action": { @@ -1390,150 +1900,75 @@ "unsubscribe_all" ] }, - "condition_ids": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Condition IDs (markets). All positions within each market are delivered.", - "maxItems": 500 - }, "position_ids": { "type": "array", "items": { "type": "string" }, - "description": "Token / asset IDs (individual outcome positions, hex strings).", - "maxItems": 500 + "description": "ERC-1155 outcome token IDs (decimal or hex strings)", + "minItems": 1 } } }, - "OrderBookSubscribeResponse": { + "PositionMetricsSubscribeResponse": { "type": "object", - "description": "Server acknowledgement for an order book subscription. Envelope type: \"order_book_stream_subscribe_response\".", + "description": "Server acknowledgement for a position metrics subscription", "properties": { - "condition_ids": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Accepted condition IDs" - }, "position_ids": { "type": "array", "items": { "type": "string" - }, - "description": "Accepted position IDs" + } }, "rejected": { "type": "array", "items": { "type": "string" - }, - "description": "Filter values that were rejected (invalid format or limit exceeded)" - } - } - }, - "WalletTrackingSubscribeMessage": { - "type": "object", - "description": "Subscribe to wallet trade alerts. wallet_addresses is required.", - "required": [ - "action", - "wallet_addresses" - ], - "properties": { - "action": { - "type": "string", - "enum": [ - "subscribe" - ] + } }, - "wallet_addresses": { - "type": "array", - "items": { - "type": "string" - }, - "description": "EVM wallet addresses to track", - "minItems": 1 + "error": { + "type": [ + "string", + "null" + ] } } }, - "TradeStreamEvent": { + "PositionMetricsEvent": { "type": "object", - "description": "Server-pushed event: a matched trade on a subscribed market/position/event/slug. Envelope type: \"trade_stream_update\".", + "description": "Server-pushed event: metrics update for one timeframe of an outcome token. Envelope type: \"position_metrics_update\". One event is emitted per timeframe window on each update.", "required": [ - "id", - "trader", - "taker", + "condition_id", "position_id", - "hash", - "block", - "confirmed_at", - "usd_amount", - "shares_amount", - "fee", - "price" + "timeframe", + "usd_volume", + "usd_buy_volume", + "usd_sell_volume", + "fees", + "txns", + "buys", + "sells", + "unique_traders", + "price_open", + "price_close", + "price_high", + "price_low", + "probability_open", + "probability_close", + "probability_high", + "probability_low", + "historical_confirmed_at", + "latest_confirmed_at", + "latest_block" ], "properties": { - "id": { - "type": "string", - "description": "Trade ID" - }, - "hash": { - "type": "string", - "description": "Transaction hash (hex)" - }, - "chain_id": { - "type": "integer", - "format": "uint64" - }, - "block": { - "type": "integer", - "format": "uint64" - }, - "confirmed_at": { - "type": "integer", - "format": "uint64", - "description": "Unix seconds" - }, - "log_index": { - "type": "integer", - "format": "uint64" - }, - "block_index": { - "type": "integer", - "format": "uint64" - }, - "order_hash": { - "type": "string", - "description": "Order hash (hex)" - }, - "trader": { - "type": "string", - "description": "Limit-order maker wallet address" - }, - "taker": { - "type": "string", - "description": "Order taker wallet address" - }, - "side": { - "type": [ - "string", - "null" - ], - "description": "\"Buy\" or \"Sell\"" - }, "condition_id": { - "type": [ - "string", - "null" - ], + "type": "string", "description": "64-char hex condition ID" }, "position_id": { "type": "string", - "description": "ERC-1155 outcome token ID (decimal string)" + "description": "ERC-1155 token ID (decimal string)" }, "outcome": { "type": [ @@ -1546,517 +1981,471 @@ "type": [ "integer", "null" - ], - "description": "0 = Yes, 1 = No" + ] }, - "question": { - "type": [ - "string", - "null" + "timeframe": { + "type": "string", + "enum": [ + "1m", + "5m", + "30m", + "1h", + "6h", + "24h", + "7d", + "30d" ] }, - "slug": { + "timestamp": { "type": [ - "string", + "integer", "null" ], - "description": "Market slug" + "format": "int64", + "description": "Optional event timestamp (Unix seconds)" }, - "event_slug": { - "type": [ - "string", - "null" - ] + "usd_volume": { + "type": "string", + "description": "Total USD volume (decimal string)" }, - "usd_amount": { + "usd_buy_volume": { "type": "string", - "description": "USD value of the trade (decimal string)" + "description": "USD buy volume (decimal string)" }, - "shares_amount": { + "usd_sell_volume": { "type": "string", - "description": "Number of shares traded (decimal string)" + "description": "USD sell volume (decimal string)" }, - "price": { - "type": "number", - "minimum": 0.0, - "maximum": 1.0, - "description": "Trade price (0–1)" + "fees": { + "type": "number" }, - "probability": { - "type": [ - "number", - "null" - ], - "description": "Implied probability (0–1)" + "txns": { + "type": "integer", + "format": "int64" }, - "fee": { - "type": "string", - "description": "Protocol fee paid (decimal string)" + "buys": { + "type": "integer", + "format": "int64" }, - "exchange": { - "type": "string", - "description": "Exchange identifier" + "sells": { + "type": "integer", + "format": "int64" }, - "trade_type": { - "type": "string", - "description": "\"OrderFilled\", \"Redemption\", \"Merge\", \"Split\", \"Cancelled\", \"PositionsConverted\", \"OrdersMatched\"" + "unique_traders": { + "type": "integer", + "format": "int64" }, - "winning_outcome_index": { - "type": [ - "integer", - "null" - ], - "description": "Resolved winning outcome index" + "price_open": { + "type": "number", + "description": "OHLC open price (0–1)" }, - "is_known_surebet": { - "type": "boolean" + "price_close": { + "type": "number", + "description": "OHLC close price (0–1)" }, - "is_coordinated": { - "type": "boolean" + "price_high": { + "type": "number", + "description": "OHLC high price (0–1)" }, - "is_surebet_trade": { - "type": "boolean" + "price_low": { + "type": "number", + "description": "OHLC low price (0–1)" }, - "surebet_price_sum": { - "type": [ - "number", - "null" - ] + "probability_open": { + "type": "number", + "description": "Implied probability at open (0–1)" }, - "is_bot": { - "type": "boolean" + "probability_close": { + "type": "number", + "description": "Implied probability at close (0–1)" }, - "bot_reason": { - "type": [ - "string", - "null" - ] + "probability_high": { + "type": "number", + "description": "Highest implied probability in window (0–1)" + }, + "probability_low": { + "type": "number", + "description": "Lowest implied probability in window (0–1)" + }, + "historical_confirmed_at": { + "type": "integer", + "format": "int64" + }, + "latest_confirmed_at": { + "type": "integer", + "format": "int64" + }, + "latest_block": { + "type": "integer", + "format": "int64" } } }, - "AssetPriceTickEvent": { + "TraderPnlSubscribeMessage": { "type": "object", - "description": "Server-pushed event: a crypto-asset price tick. Envelope type: \"asset_price_tick\".", + "description": "Subscribe to the trader PnL stream. traders is required and must be non-empty.", "required": [ - "event_type", - "symbol", - "price", - "timestamp_ms", - "published_at" + "action", + "traders" ], "properties": { - "event_type": { - "type": "string", - "description": "Always \"asset_price_tick\"" - }, - "symbol": { + "action": { "type": "string", - "description": "Uppercase asset symbol (e.g. \"BTC\")" + "enum": [ + "subscribe", + "unsubscribe_all" + ] }, - "price": { - "type": "number", - "description": "Current price in USD" + "traders": { + "type": "array", + "items": { + "type": "string" + }, + "description": "EVM wallet addresses", + "minItems": 1 + } + } + }, + "TraderPnlSubscribeResponse": { + "type": "object", + "description": "Server acknowledgement for a trader PnL subscription", + "properties": { + "traders": { + "type": "array", + "items": { + "type": "string" + } }, - "timestamp_ms": { - "type": "integer", - "format": "int64", - "description": "Event timestamp in Unix milliseconds" + "rejected": { + "type": "array", + "items": { + "type": "string" + } }, - "published_at": { - "type": "integer", - "format": "int64", - "description": "Publish timestamp in Unix milliseconds" + "error": { + "type": [ + "string", + "null" + ] } } }, - "AssetPriceWindowUpdateEvent": { + "TraderGlobalPnlEvent": { "type": "object", - "description": "Server-pushed event: candle open or close for a crypto asset. Envelope type: \"asset_price_window_update\". Delivered from both `polymarket_asset_prices` and `polymarket_asset_window_updates` rooms.", + "description": "Server-pushed event: global (portfolio-level) PnL update for a trader. Envelope type: \"trader_global_pnl_update\".", "required": [ - "event_type", - "symbol", - "variant", - "start_time", - "end_time", - "open_price", - "close_price", - "update_type", - "published_at" + "trader", + "realized_pnl_usd", + "total_volume_usd", + "buy_volume_usd", + "sell_volume_usd", + "redemption_volume_usd", + "merge_volume_usd", + "market_win_rate_pct", + "avg_pnl_per_market", + "avg_pnl_per_trade", + "avg_hold_time_seconds", + "total_fees", + "best_trade_pnl_usd", + "worst_trade_pnl_usd" ], "properties": { - "event_type": { + "trader": { "type": "string", - "description": "Always \"asset_price_window_update\"" + "description": "Trader EVM wallet address" }, - "symbol": { + "realized_pnl_usd": { "type": "string", - "description": "Uppercase asset symbol (e.g. \"BTC\")" + "description": "Total realized PnL in USD (decimal string)" }, - "variant": { - "type": "string", - "description": "Candle size / timeframe (e.g. \"5m\", \"1h\", \"1d\")" + "events_traded": { + "type": [ + "integer", + "null" + ], + "format": "int64" }, - "start_time": { - "type": "integer", - "format": "int64", - "description": "Candle start in Unix milliseconds" + "markets_traded": { + "type": [ + "integer", + "null" + ], + "format": "int64" }, - "end_time": { - "type": "integer", - "format": "int64", - "description": "Candle end in Unix milliseconds" + "total_buys": { + "type": [ + "integer", + "null" + ], + "format": "int64" }, - "open_price": { - "type": "number", - "description": "Candle open price in USD" + "total_sells": { + "type": [ + "integer", + "null" + ], + "format": "int64" }, - "close_price": { - "type": "number", - "description": "Candle close price in USD" + "total_redemptions": { + "type": [ + "integer", + "null" + ], + "format": "int64" }, - "update_type": { - "type": "string", - "description": "\"open\" = candle starting, \"close\" = candle finalised" + "total_merges": { + "type": [ + "integer", + "null" + ], + "format": "int64" }, - "published_at": { - "type": "integer", - "format": "int64", - "description": "Publish timestamp in Unix milliseconds" - } - } - }, - "AssetWindowUpdateEvent": { - "allOf": [ - { - "$ref": "#/components/schemas/AssetPriceWindowUpdateEvent" - } - ], - "description": "Server-pushed event from the polymarket_asset_window_updates room. Same payload as AssetPriceWindowUpdateEvent. Envelope type: \"asset_price_window_update\"." - }, - "MarketMetricsEvent": { - "type": "object", - "description": "Server-pushed event: metrics update for one timeframe of a condition. Envelope type: \"market_metrics_update\". One event is emitted per timeframe window on each update.", - "required": [ - "condition_id", - "timeframe", - "usd_volume", - "fees", - "txns", - "unique_traders", - "historical_confirmed_at", - "latest_confirmed_at", - "latest_block" - ], - "properties": { - "condition_id": { + "total_volume_usd": { "type": "string", - "description": "64-char hex condition ID" + "description": "Total USD volume (decimal string)" }, - "timeframe": { - "type": "string", - "enum": [ - "1m", - "5m", - "30m", - "1h", - "6h", - "24h", - "7d", - "30d" - ] + "buy_volume_usd": { + "type": "string" }, - "timestamp": { + "sell_volume_usd": { + "type": "string" + }, + "redemption_volume_usd": { + "type": "string" + }, + "merge_volume_usd": { + "type": "string" + }, + "markets_won": { "type": [ "integer", "null" ], - "format": "int64", - "description": "Optional event timestamp (Unix seconds)" + "format": "int64" }, - "usd_volume": { + "markets_lost": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "market_win_rate_pct": { "type": "string", - "description": "USD volume in this timeframe window (decimal string)" + "description": "Win rate percentage (decimal string)" }, - "fees": { - "type": "number", - "description": "Total fees in this window" + "avg_pnl_per_market": { + "type": "string" }, - "txns": { - "type": "integer", - "format": "int64", - "description": "Number of transactions" + "avg_pnl_per_trade": { + "type": "string" }, - "unique_traders": { - "type": "integer", - "format": "int64" + "avg_hold_time_seconds": { + "type": "string" }, - "historical_confirmed_at": { - "type": "integer", + "total_fees": { + "type": "string" + }, + "best_trade_pnl_usd": { + "type": "string" + }, + "best_trade_condition_id": { + "type": [ + "string", + "null" + ] + }, + "worst_trade_pnl_usd": { + "type": "string" + }, + "worst_trade_condition_id": { + "type": [ + "string", + "null" + ] + }, + "first_trade_at": { + "type": [ + "integer", + "null" + ], "format": "int64", - "description": "Earliest trade timestamp in window (Unix seconds)" + "description": "Unix seconds" }, - "latest_confirmed_at": { - "type": "integer", + "last_trade_at": { + "type": [ + "integer", + "null" + ], "format": "int64", - "description": "Latest trade timestamp in window (Unix seconds)" + "description": "Unix seconds" }, - "latest_block": { - "type": "integer", + "timestamp": { + "type": [ + "integer", + "null" + ], "format": "int64" + }, + "timeframe": { + "type": [ + "string", + "null" + ], + "description": "\"1d\", \"7d\", \"30d\", or \"lifetime\"" } } }, - "EventMetricsEvent": { + "TraderMarketPnlEvent": { "type": "object", - "description": "Server-pushed event: aggregated metrics update for one timeframe of an event. Envelope type: \"event_metrics_update\". One event is emitted per timeframe window on each update.", + "description": "Server-pushed event: per-market PnL update for a trader. Envelope type: \"trader_market_pnl_update\".", "required": [ - "event_slug", - "timeframe", - "usd_volume", - "fees", - "txns", - "unique_traders", - "historical_confirmed_at", - "latest_confirmed_at", - "latest_block" + "trader", + "condition_id", + "buy_usd", + "sell_usd", + "redemption_usd", + "merge_usd", + "realized_pnl_usd", + "total_fees" ], "properties": { - "event_slug": { + "trader": { "type": "string" }, - "timeframe": { + "condition_id": { "type": "string", - "enum": [ - "1m", - "5m", - "30m", - "1h", - "6h", - "24h", - "7d", - "30d" + "description": "64-char hex condition ID" + }, + "event_slug": { + "type": [ + "string", + "null" ] }, - "timestamp": { + "outcomes_traded": { "type": [ "integer", "null" ], - "format": "int64", - "description": "Optional event timestamp (Unix seconds)" - }, - "usd_volume": { - "type": "string", - "description": "USD volume in this timeframe window (decimal string)" - }, - "fees": { - "type": "number" - }, - "txns": { - "type": "integer", "format": "int64" }, - "unique_traders": { - "type": "integer", + "total_buys": { + "type": [ + "integer", + "null" + ], "format": "int64" }, - "historical_confirmed_at": { - "type": "integer", + "total_sells": { + "type": [ + "integer", + "null" + ], "format": "int64" }, - "latest_confirmed_at": { - "type": "integer", + "total_redemptions": { + "type": [ + "integer", + "null" + ], "format": "int64" }, - "latest_block": { - "type": "integer", + "total_merges": { + "type": [ + "integer", + "null" + ], "format": "int64" - } - } - }, - "PositionMetricsEvent": { - "type": "object", - "description": "Server-pushed event: metrics update for one timeframe of an outcome token. Envelope type: \"position_metrics_update\". One event is emitted per timeframe window on each update.", - "required": [ - "condition_id", - "position_id", - "timeframe", - "usd_volume", - "usd_buy_volume", - "usd_sell_volume", - "fees", - "txns", - "buys", - "sells", - "unique_traders", - "price_open", - "price_close", - "price_high", - "price_low", - "probability_open", - "probability_close", - "probability_high", - "probability_low", - "historical_confirmed_at", - "latest_confirmed_at", - "latest_block" - ], - "properties": { - "condition_id": { + }, + "buy_usd": { "type": "string", - "description": "64-char hex condition ID" + "description": "Total buy volume in USD (decimal string)" }, - "position_id": { + "sell_usd": { + "type": "string" + }, + "redemption_usd": { + "type": "string" + }, + "merge_usd": { + "type": "string" + }, + "realized_pnl_usd": { "type": "string", - "description": "ERC-1155 token ID (decimal string)" + "description": "Realized PnL in USD (decimal string)" }, - "outcome": { + "winning_outcomes": { "type": [ - "string", + "integer", "null" ], - "description": "Outcome name (e.g. \"Yes\")" + "format": "int64" }, - "outcome_index": { + "total_fees": { + "type": "string" + }, + "first_trade_at": { "type": [ "integer", "null" - ] - }, - "timeframe": { - "type": "string", - "enum": [ - "1m", - "5m", - "30m", - "1h", - "6h", - "24h", - "7d", - "30d" - ] + ], + "format": "int64", + "description": "Unix seconds" }, - "timestamp": { + "last_trade_at": { "type": [ "integer", "null" ], "format": "int64", - "description": "Optional event timestamp (Unix seconds)" - }, - "usd_volume": { - "type": "string", - "description": "Total USD volume (decimal string)" - }, - "usd_buy_volume": { - "type": "string", - "description": "USD buy volume (decimal string)" - }, - "usd_sell_volume": { - "type": "string", - "description": "USD sell volume (decimal string)" - }, - "fees": { - "type": "number" - }, - "txns": { - "type": "integer", - "format": "int64" - }, - "buys": { - "type": "integer", - "format": "int64" - }, - "sells": { - "type": "integer", - "format": "int64" - }, - "unique_traders": { - "type": "integer", - "format": "int64" - }, - "price_open": { - "type": "number", - "description": "OHLC open price (0–1)" - }, - "price_close": { - "type": "number", - "description": "OHLC close price (0–1)" - }, - "price_high": { - "type": "number", - "description": "OHLC high price (0–1)" - }, - "price_low": { - "type": "number", - "description": "OHLC low price (0–1)" - }, - "probability_open": { - "type": "number", - "description": "Implied probability at open (0–1)" - }, - "probability_close": { - "type": "number", - "description": "Implied probability at close (0–1)" - }, - "probability_high": { - "type": "number", - "description": "Highest implied probability in window (0–1)" - }, - "probability_low": { - "type": "number", - "description": "Lowest implied probability in window (0–1)" - }, - "historical_confirmed_at": { - "type": "integer", - "format": "int64" + "description": "Unix seconds" }, - "latest_confirmed_at": { - "type": "integer", + "timestamp": { + "type": [ + "integer", + "null" + ], "format": "int64" }, - "latest_block": { - "type": "integer", - "format": "int64" + "timeframe": { + "type": [ + "string", + "null" + ], + "description": "\"1d\", \"7d\", \"30d\", or \"lifetime\"" } } }, - "TraderGlobalPnlEvent": { + "TraderEventPnlEvent": { "type": "object", - "description": "Server-pushed event: global (portfolio-level) PnL update for a trader. Envelope type: \"trader_global_pnl_update\".", + "description": "Server-pushed event: per-event PnL update for a trader. Envelope type: \"trader_event_pnl_update\".", "required": [ "trader", - "realized_pnl_usd", + "event_slug", + "buy_usd", + "sell_usd", + "redemption_usd", + "merge_usd", "total_volume_usd", - "buy_volume_usd", - "sell_volume_usd", - "redemption_volume_usd", - "merge_volume_usd", - "market_win_rate_pct", - "avg_pnl_per_market", - "avg_pnl_per_trade", - "avg_hold_time_seconds", - "total_fees", - "best_trade_pnl_usd", - "worst_trade_pnl_usd" + "realized_pnl_usd", + "total_fees" ], "properties": { "trader": { - "type": "string", - "description": "Trader EVM wallet address" + "type": "string" }, - "realized_pnl_usd": { - "type": "string", - "description": "Total realized PnL in USD (decimal string)" + "event_slug": { + "type": "string" }, - "events_traded": { + "markets_traded": { "type": [ "integer", "null" ], "format": "int64" }, - "markets_traded": { + "outcomes_traded": { "type": [ "integer", "null" @@ -2095,66 +2484,39 @@ "type": "string", "description": "Total USD volume (decimal string)" }, - "buy_volume_usd": { + "buy_usd": { "type": "string" }, - "sell_volume_usd": { + "sell_usd": { "type": "string" }, - "redemption_volume_usd": { + "redemption_usd": { "type": "string" }, - "merge_volume_usd": { + "merge_usd": { "type": "string" }, - "markets_won": { + "realized_pnl_usd": { + "type": "string", + "description": "Realized PnL in USD (decimal string)" + }, + "winning_markets": { "type": [ "integer", "null" ], "format": "int64" }, - "markets_lost": { + "losing_markets": { "type": [ "integer", "null" ], "format": "int64" }, - "market_win_rate_pct": { - "type": "string", - "description": "Win rate percentage (decimal string)" - }, - "avg_pnl_per_market": { - "type": "string" - }, - "avg_pnl_per_trade": { - "type": "string" - }, - "avg_hold_time_seconds": { - "type": "string" - }, "total_fees": { "type": "string" }, - "best_trade_pnl_usd": { - "type": "string" - }, - "best_trade_condition_id": { - "type": [ - "string", - "null" - ] - }, - "worst_trade_pnl_usd": { - "type": "string" - }, - "worst_trade_condition_id": { - "type": [ - "string", - "null" - ] - }, "first_trade_at": { "type": [ "integer", @@ -2187,256 +2549,52 @@ } } }, - "TraderMarketPnlEvent": { + "TraderPositionsSubscribeMessage": { "type": "object", - "description": "Server-pushed event: per-market PnL update for a trader. Envelope type: \"trader_market_pnl_update\".", + "description": "Subscribe to the trader positions stream. traders is required and must be non-empty.", "required": [ - "trader", - "condition_id", - "buy_usd", - "sell_usd", - "redemption_usd", - "merge_usd", - "realized_pnl_usd", - "total_fees" + "action", + "traders" ], "properties": { - "trader": { - "type": "string" - }, - "condition_id": { + "action": { "type": "string", - "description": "64-char hex condition ID" - }, - "event_slug": { - "type": [ - "string", - "null" + "enum": [ + "subscribe", + "unsubscribe_all" ] }, - "outcomes_traded": { - "type": [ - "integer", - "null" - ], - "format": "int64" - }, - "total_buys": { - "type": [ - "integer", - "null" - ], - "format": "int64" - }, - "total_sells": { - "type": [ - "integer", - "null" - ], - "format": "int64" - }, - "total_redemptions": { - "type": [ - "integer", - "null" - ], - "format": "int64" - }, - "total_merges": { - "type": [ - "integer", - "null" - ], - "format": "int64" - }, - "buy_usd": { - "type": "string", - "description": "Total buy volume in USD (decimal string)" - }, - "sell_usd": { - "type": "string" - }, - "redemption_usd": { - "type": "string" - }, - "merge_usd": { - "type": "string" - }, - "realized_pnl_usd": { - "type": "string", - "description": "Realized PnL in USD (decimal string)" - }, - "winning_outcomes": { - "type": [ - "integer", - "null" - ], - "format": "int64" - }, - "total_fees": { - "type": "string" - }, - "first_trade_at": { - "type": [ - "integer", - "null" - ], - "format": "int64", - "description": "Unix seconds" - }, - "last_trade_at": { - "type": [ - "integer", - "null" - ], - "format": "int64", - "description": "Unix seconds" - }, - "timestamp": { - "type": [ - "integer", - "null" - ], - "format": "int64" - }, - "timeframe": { - "type": [ - "string", - "null" - ], - "description": "\"1d\", \"7d\", \"30d\", or \"lifetime\"" + "traders": { + "type": "array", + "items": { + "type": "string" + }, + "description": "EVM wallet addresses", + "minItems": 1 } } }, - "TraderEventPnlEvent": { + "TraderPositionsSubscribeResponse": { "type": "object", - "description": "Server-pushed event: per-event PnL update for a trader. Envelope type: \"trader_event_pnl_update\".", - "required": [ - "trader", - "event_slug", - "buy_usd", - "sell_usd", - "redemption_usd", - "merge_usd", - "total_volume_usd", - "realized_pnl_usd", - "total_fees" - ], + "description": "Server acknowledgement for a trader positions subscription", "properties": { - "trader": { - "type": "string" - }, - "event_slug": { - "type": "string" - }, - "markets_traded": { - "type": [ - "integer", - "null" - ], - "format": "int64" - }, - "outcomes_traded": { - "type": [ - "integer", - "null" - ], - "format": "int64" - }, - "total_buys": { - "type": [ - "integer", - "null" - ], - "format": "int64" - }, - "total_sells": { - "type": [ - "integer", - "null" - ], - "format": "int64" - }, - "total_redemptions": { - "type": [ - "integer", - "null" - ], - "format": "int64" - }, - "total_merges": { - "type": [ - "integer", - "null" - ], - "format": "int64" - }, - "total_volume_usd": { - "type": "string", - "description": "Total USD volume (decimal string)" - }, - "buy_usd": { - "type": "string" - }, - "sell_usd": { - "type": "string" - }, - "redemption_usd": { - "type": "string" - }, - "merge_usd": { - "type": "string" - }, - "realized_pnl_usd": { - "type": "string", - "description": "Realized PnL in USD (decimal string)" - }, - "winning_markets": { - "type": [ - "integer", - "null" - ], - "format": "int64" - }, - "losing_markets": { - "type": [ - "integer", - "null" - ], - "format": "int64" - }, - "total_fees": { - "type": "string" - }, - "first_trade_at": { - "type": [ - "integer", - "null" - ], - "format": "int64", - "description": "Unix seconds" - }, - "last_trade_at": { - "type": [ - "integer", - "null" - ], - "format": "int64", - "description": "Unix seconds" + "traders": { + "type": "array", + "items": { + "type": "string" + } }, - "timestamp": { - "type": [ - "integer", - "null" - ], - "format": "int64" + "rejected": { + "type": "array", + "items": { + "type": "string" + } }, - "timeframe": { + "error": { "type": [ "string", "null" - ], - "description": "\"1d\", \"7d\", \"30d\", or \"lifetime\"" + ] } } }, @@ -2611,15 +2769,81 @@ } } }, - "AccountsUpdateEvent": { + "AccountsSubscribeMessage": { "type": "object", - "description": "Server-pushed event: ERC-1155 outcome token balance change for a wallet. Envelope type: \"accounts_update\".", + "description": "Subscribe to the accounts stream. `wallets` is required. Share balance updates (`accounts_update`) are always delivered. Set `include_usdce` or `include_matic` to also receive those balance streams.", "required": [ - "wallet", - "position_id", - "balance", - "block_number", - "updated_at" + "action", + "wallets" + ], + "properties": { + "action": { + "type": "string", + "enum": [ + "subscribe", + "unsubscribe_all" + ] + }, + "wallets": { + "type": "array", + "items": { + "type": "string" + }, + "description": "EVM wallet addresses", + "minItems": 1 + }, + "include_usdce": { + "type": "boolean", + "default": false, + "description": "Also stream USDCe collateral balance updates for subscribed wallets" + }, + "include_matic": { + "type": "boolean", + "default": false, + "description": "Also stream MATIC gas balance updates for subscribed wallets" + } + } + }, + "AccountsSubscribeResponse": { + "type": "object", + "description": "Server acknowledgement for an accounts subscription", + "properties": { + "wallets": { + "type": "array", + "items": { + "type": "string" + } + }, + "rejected": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Addresses rejected (invalid format)" + }, + "include_usdce": { + "type": "boolean" + }, + "include_matic": { + "type": "boolean" + }, + "error": { + "type": [ + "string", + "null" + ] + } + } + }, + "AccountsUpdateEvent": { + "type": "object", + "description": "Server-pushed event: ERC-1155 outcome token balance change for a wallet. Envelope type: \"accounts_update\".", + "required": [ + "wallet", + "position_id", + "balance", + "block_number", + "updated_at" ], "properties": { "wallet": { @@ -2684,6 +2908,6896 @@ "description": "Unix seconds" } } + }, + "MaticUpdateEvent": { + "type": "object", + "description": "Server-pushed event: MATIC native balance change for a wallet. Envelope type: \"matic_update\". Only delivered when `include_matic: true`.", + "required": [ + "address", + "block_number", + "updated_at" + ], + "properties": { + "address": { + "type": "string", + "description": "Wallet address (0x-prefixed hex)" + }, + "token_address": { + "type": "string", + "description": "Native token address — omitted when not available" + }, + "balance": { + "type": "string", + "description": "Current MATIC balance (decimal string) — omitted when not available" + }, + "block_number": { + "type": "integer", + "format": "uint64" + }, + "updated_at": { + "type": "integer", + "format": "int64", + "description": "Unix seconds" + } + } + }, + "OrderBookSubscribeMessage": { + "type": "object", + "description": "Subscribe to the order book stream. At least one filter is required. Maximum 500 combined condition_ids + position_ids per client. No `type` field is needed — the server routes by room_id.", + "required": [ + "action" + ], + "properties": { + "action": { + "type": "string", + "enum": [ + "subscribe", + "unsubscribe_all" + ] + }, + "condition_ids": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Condition IDs (markets). All positions within each market are delivered.", + "maxItems": 500 + }, + "position_ids": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Token / asset IDs (individual outcome positions, hex strings).", + "maxItems": 500 + } + } + }, + "OrderBookSubscribeResponse": { + "type": "object", + "description": "Server acknowledgement for an order book subscription. Envelope type: \"order_book_stream_subscribe_response\".", + "properties": { + "condition_ids": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Accepted condition IDs" + }, + "position_ids": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Accepted position IDs" + }, + "rejected": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Filter values that were rejected (invalid format or limit exceeded)" + } + } + }, + "OrderBookLevel": { + "type": "array", + "description": "A single price level: [price_string, size_string]", + "items": { + "type": "string" + }, + "minItems": 2, + "maxItems": 2 + }, + "OrderBookUpdateEvent": { + "type": "object", + "description": "Server-pushed event: full CLOB orderbook snapshot for an outcome token. Envelope type: \"order_book_update\". Delivered whenever the book changes for a subscribed condition or position.", + "required": [ + "asset_id", + "market", + "bids", + "asks", + "timestamp", + "hash" + ], + "properties": { + "asset_id": { + "type": "string", + "description": "Hex token ID (position / outcome token)" + }, + "market": { + "type": "string", + "description": "Condition ID (hex)" + }, + "bids": { + "type": "array", + "items": { + "$ref": "#/components/schemas/OrderBookLevel" + }, + "description": "Bid levels sorted best-first (highest price first)" + }, + "asks": { + "type": "array", + "items": { + "$ref": "#/components/schemas/OrderBookLevel" + }, + "description": "Ask levels sorted best-first (lowest price first)" + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix milliseconds from CLOB message" + }, + "hash": { + "type": "string", + "description": "Orderbook content hash — identical hash means no change" + }, + "best_bid": { + "type": [ + "number", + "null" + ], + "description": "Best bid price (0–1)" + }, + "best_ask": { + "type": [ + "number", + "null" + ], + "description": "Best ask price (0–1)" + }, + "mid_price": { + "type": [ + "number", + "null" + ], + "description": "(best_bid + best_ask) / 2" + }, + "spread": { + "type": [ + "number", + "null" + ], + "description": "best_ask − best_bid" + }, + "bid_liquidity_usd": { + "type": [ + "number", + "null" + ], + "description": "Total USD value of all bid levels" + }, + "ask_liquidity_usd": { + "type": [ + "number", + "null" + ], + "description": "Total USD value of all ask levels" + }, + "bid_levels": { + "type": [ + "integer", + "null" + ], + "description": "Number of bid price levels" + }, + "ask_levels": { + "type": [ + "integer", + "null" + ], + "description": "Number of ask price levels" + } + } + }, + "ClobRewardsSubscribeMessage": { + "type": "object", + "description": "Subscribe to CLOB reward changes. Either provide specific condition_ids or set subscribe_all to true.", + "required": [ + "action" + ], + "properties": { + "action": { + "type": "string", + "enum": [ + "subscribe", + "unsubscribe_all" + ] + }, + "condition_ids": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Condition IDs to watch for reward changes.", + "maxItems": 500 + }, + "subscribe_all": { + "type": "boolean", + "description": "If true, receive ALL reward changes across all markets. Overrides condition_ids.", + "default": false + } + } + }, + "ClobRewardsSubscribeResponse": { + "type": "object", + "description": "Server acknowledgement for a CLOB rewards subscription. Envelope type: \"clob_rewards_stream_subscribe_response\".", + "properties": { + "condition_ids": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Accepted condition IDs" + }, + "subscribe_all": { + "type": "boolean", + "description": "Whether subscribed to all changes" + }, + "rejected": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Filter values that were rejected" + } + } + }, + "ClobRewardsUpdateEvent": { + "type": "object", + "description": "Server-pushed CLOB reward change event. Envelope type: \"clob_rewards_update\".", + "properties": { + "event_type": { + "type": "string", + "enum": [ + "added", + "removed", + "updated" + ], + "description": "Type of change" + }, + "condition_id": { + "type": "string", + "description": "Affected market condition ID" + }, + "reward": { + "type": [ + "object", + "null" + ], + "description": "Full reward state (null for 'removed' events)", + "properties": { + "condition_id": { + "type": "string" + }, + "rewards_config": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "asset_address": { + "type": "string", + "description": "Reward token address (e.g. USDC)" + }, + "start_date": { + "type": "string", + "format": "date" + }, + "end_date": { + "type": "string", + "format": "date" + }, + "rate_per_day": { + "type": "number", + "description": "Daily reward rate in USDC" + }, + "total_rewards": { + "type": "number", + "description": "Cumulative rewards distributed" + } + } + } + }, + "rewards_max_spread": { + "type": [ + "number", + "null" + ], + "description": "Max spread to qualify for rewards" + }, + "rewards_min_size": { + "type": [ + "number", + "null" + ], + "description": "Min order size to qualify for rewards" + }, + "native_daily_rate": { + "type": [ + "number", + "null" + ], + "description": "Native (non-sponsored) daily rate" + }, + "sponsored_daily_rate": { + "type": [ + "number", + "null" + ], + "description": "Sponsored daily rate" + }, + "total_daily_rate": { + "type": [ + "number", + "null" + ], + "description": "Combined daily rate (native + sponsored)" + }, + "sponsors_count": { + "type": [ + "integer", + "null" + ], + "description": "Number of sponsors" + } + } + }, + "timestamp_ms": { + "type": "integer", + "description": "Unix timestamp in milliseconds" + } + } + }, + "WalletTrackingSubscribeMessage": { + "type": "object", + "description": "Subscribe to wallet trade alerts. wallet_addresses is required.", + "required": [ + "action", + "wallet_addresses" + ], + "properties": { + "action": { + "type": "string", + "enum": [ + "subscribe" + ] + }, + "wallet_addresses": { + "type": "array", + "items": { + "type": "string" + }, + "description": "EVM wallet addresses to track", + "minItems": 1 + } + } + }, + "WalletTrackingSubscribeResponse": { + "type": "object", + "description": "Server acknowledgement for a wallet tracking subscription", + "required": [ + "subscribed_count", + "current_user_wallets", + "total_wallets" + ], + "properties": { + "subscribed_count": { + "type": "integer", + "format": "uint64", + "description": "Number of wallets successfully subscribed" + }, + "invalid_addresses": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Addresses rejected (invalid format)" + }, + "current_user_wallets": { + "type": "array", + "items": { + "type": "string" + }, + "description": "All wallet addresses currently tracked by this user" + }, + "total_wallets": { + "type": "integer", + "format": "uint64", + "description": "Total wallet count for this user" + } + } + }, + "PredictionMarketMetadata": { + "type": "object", + "description": "Market metadata enrichment attached to wallet tracking alerts", + "properties": { + "slug": { + "type": [ + "string", + "null" + ], + "description": "Market slug" + }, + "question": { + "type": [ + "string", + "null" + ], + "description": "Market question text" + }, + "outcome": { + "type": [ + "string", + "null" + ], + "description": "Outcome name (e.g. \"Yes\")" + }, + "outcome_index": { + "type": [ + "integer", + "null" + ] + }, + "image_url": { + "type": [ + "string", + "null" + ] + } + } + }, + "WalletTrackingAlertEvent": { + "type": "object", + "description": "Server-pushed event: a trade executed by a tracked wallet. Envelope type: \"wallet_tracking_alert\".", + "required": [ + "is_buy", + "trader", + "position_id", + "usd_amount", + "shares_amount", + "price", + "confirmed_at" + ], + "properties": { + "is_buy": { + "type": "boolean", + "description": "True = buy, false = sell" + }, + "trader": { + "type": "string", + "description": "Trader EVM wallet address (lowercase)" + }, + "condition_id": { + "type": [ + "string", + "null" + ], + "description": "64-char hex condition ID" + }, + "position_id": { + "type": "string", + "description": "ERC-1155 outcome token ID (decimal string)" + }, + "usd_amount": { + "type": "string", + "description": "USD value of the trade (decimal string, 6dp)" + }, + "shares_amount": { + "type": "string", + "description": "Number of shares traded (decimal string, 6dp)" + }, + "price": { + "type": "number", + "minimum": 0.0, + "maximum": 1.0, + "description": "Trade price (0–1)" + }, + "probability": { + "type": [ + "number", + "null" + ], + "description": "Implied probability (0–1)" + }, + "metadata": { + "oneOf": [ + { + "$ref": "#/components/schemas/PredictionMarketMetadata" + }, + { + "type": "null" + } + ], + "description": "Market metadata — null when enrichment is unavailable" + }, + "confirmed_at": { + "type": "integer", + "format": "int64", + "description": "Unix seconds" + } + } + }, + "FirstTradePayload": { + "type": "object", + "description": "Payload delivered when a tracked trader executes their first-ever trade on Polymarket", + "required": [ + "trader", + "taker", + "position_id", + "trade_id", + "hash", + "block", + "confirmed_at", + "amount_usd", + "shares_amount", + "fee", + "side", + "price", + "exchange", + "trade_type" + ], + "properties": { + "trader": { + "type": "string", + "description": "Limit-order maker wallet address (lowercase)" + }, + "taker": { + "type": "string", + "description": "Order filler wallet address (lowercase)" + }, + "position_id": { + "type": "string", + "description": "ERC-1155 outcome token ID" + }, + "condition_id": { + "type": [ + "string", + "null" + ], + "description": "Parent market condition ID (0x-prefixed hex)" + }, + "outcome": { + "type": [ + "string", + "null" + ], + "description": "Outcome name (e.g. \"Yes\", \"No\")" + }, + "outcome_index": { + "type": [ + "integer", + "null" + ], + "description": "Outcome index: 0 = Yes/Up, 1 = No" + }, + "question": { + "type": [ + "string", + "null" + ], + "description": "Market question text" + }, + "market_slug": { + "type": [ + "string", + "null" + ], + "description": "Market slug" + }, + "event_slug": { + "type": [ + "string", + "null" + ], + "description": "Parent event slug" + }, + "trade_id": { + "type": "string", + "description": "Unique trade identifier" + }, + "hash": { + "type": "string", + "description": "Transaction hash" + }, + "block": { + "type": "integer", + "format": "int64", + "description": "Block number" + }, + "confirmed_at": { + "type": "integer", + "format": "int64", + "description": "Block confirmation timestamp (Unix seconds)" + }, + "amount_usd": { + "type": "number", + "description": "USD size of the trade (6 decimal places)" + }, + "shares_amount": { + "type": "number", + "description": "Outcome shares traded (6 decimal places)" + }, + "fee": { + "type": "number", + "description": "Fee paid in USD (6 decimal places)" + }, + "side": { + "type": "string", + "enum": [ + "Buy", + "Sell" + ], + "description": "Trade direction" + }, + "price": { + "type": "number", + "minimum": 0.0, + "maximum": 1.0, + "description": "Outcome token price (0.0–1.0)" + }, + "exchange": { + "type": "string", + "description": "Exchange identifier" + }, + "trade_type": { + "type": "string", + "description": "Trade type identifier" + } + } + }, + "NewMarketPayload": { + "type": "object", + "description": "Payload delivered when a trader places their first trade in a specific market (fires once per trader+market pair)", + "required": [ + "trader", + "taker", + "position_id", + "trade_id", + "hash", + "block", + "confirmed_at", + "amount_usd", + "shares_amount", + "fee", + "side", + "price", + "exchange", + "trade_type" + ], + "properties": { + "trader": { + "type": "string", + "description": "Limit-order maker wallet address (lowercase)" + }, + "taker": { + "type": "string", + "description": "Order filler wallet address (lowercase)" + }, + "position_id": { + "type": "string", + "description": "ERC-1155 outcome token ID" + }, + "condition_id": { + "type": [ + "string", + "null" + ], + "description": "Parent market condition ID" + }, + "outcome": { + "type": [ + "string", + "null" + ], + "description": "Outcome name (e.g. \"Yes\", \"No\")" + }, + "outcome_index": { + "type": [ + "integer", + "null" + ], + "description": "Outcome index: 0 = Yes/Up, 1 = No" + }, + "question": { + "type": [ + "string", + "null" + ], + "description": "Market question text" + }, + "market_slug": { + "type": [ + "string", + "null" + ], + "description": "Market slug" + }, + "event_slug": { + "type": [ + "string", + "null" + ], + "description": "Parent event slug" + }, + "trade_id": { + "type": "string", + "description": "Unique trade identifier" + }, + "hash": { + "type": "string", + "description": "Transaction hash" + }, + "block": { + "type": "integer", + "format": "int64", + "description": "Block number" + }, + "confirmed_at": { + "type": "integer", + "format": "int64", + "description": "Block confirmation timestamp (Unix seconds)" + }, + "amount_usd": { + "type": "number", + "description": "USD size of the trade (6 decimal places)" + }, + "shares_amount": { + "type": "number", + "description": "Outcome shares traded (6 decimal places)" + }, + "fee": { + "type": "number", + "description": "Fee paid in USD (6 decimal places)" + }, + "side": { + "type": "string", + "enum": [ + "Buy", + "Sell" + ], + "description": "Trade direction" + }, + "price": { + "type": "number", + "minimum": 0.0, + "maximum": 1.0, + "description": "Outcome token price (0.0–1.0)" + }, + "probability": { + "type": [ + "number", + "null" + ], + "minimum": 0.0, + "maximum": 1.0, + "description": "Implied probability (0.0–1.0); null when outcome is unknown" + }, + "exchange": { + "type": "string", + "description": "Exchange identifier" + }, + "trade_type": { + "type": "string", + "description": "Trade type identifier" + } + } + }, + "WhaleTradePayload": { + "type": "object", + "description": "Payload delivered when a trade exceeds the configured size and probability thresholds", + "required": [ + "trader", + "taker", + "position_id", + "trade_id", + "hash", + "block", + "confirmed_at", + "amount_usd", + "shares_amount", + "fee", + "side", + "price", + "exchange", + "trade_type" + ], + "properties": { + "trader": { + "type": "string", + "description": "Limit-order maker wallet address (lowercase)" + }, + "taker": { + "type": "string", + "description": "Order filler wallet address (lowercase)" + }, + "position_id": { + "type": "string", + "description": "ERC-1155 outcome token ID" + }, + "condition_id": { + "type": [ + "string", + "null" + ], + "description": "Parent market condition ID" + }, + "outcome": { + "type": [ + "string", + "null" + ], + "description": "Outcome name (e.g. \"Yes\", \"No\")" + }, + "outcome_index": { + "type": [ + "integer", + "null" + ], + "description": "Outcome index: 0 = Yes/Up, 1 = No" + }, + "question": { + "type": [ + "string", + "null" + ], + "description": "Market question text" + }, + "market_slug": { + "type": [ + "string", + "null" + ], + "description": "Market slug" + }, + "event_slug": { + "type": [ + "string", + "null" + ], + "description": "Parent event slug" + }, + "trade_id": { + "type": "string", + "description": "Unique trade identifier" + }, + "hash": { + "type": "string", + "description": "Transaction hash" + }, + "block": { + "type": "integer", + "format": "int64", + "description": "Block number" + }, + "confirmed_at": { + "type": "integer", + "format": "int64", + "description": "Block confirmation timestamp (Unix seconds)" + }, + "amount_usd": { + "type": "number", + "description": "USD size of the trade (6 decimal places)" + }, + "shares_amount": { + "type": "number", + "description": "Outcome shares traded (6 decimal places)" + }, + "fee": { + "type": "number", + "description": "Fee paid in USD (6 decimal places)" + }, + "side": { + "type": "string", + "enum": [ + "Buy", + "Sell" + ], + "description": "Trade direction" + }, + "price": { + "type": "number", + "minimum": 0.0, + "maximum": 1.0, + "description": "Outcome token price (0.0–1.0)" + }, + "probability": { + "type": [ + "number", + "null" + ], + "minimum": 0.0, + "maximum": 1.0, + "description": "Implied probability (0.0–1.0); null when outcome is unknown" + }, + "exchange": { + "type": "string", + "description": "Exchange identifier" + }, + "trade_type": { + "type": "string", + "description": "Trade type identifier" + } + } + }, + "NewTradePayload": { + "type": "object", + "description": "Payload delivered on every order-filled trade", + "required": [ + "trader", + "taker", + "position_id", + "trade_id", + "hash", + "block", + "confirmed_at", + "amount_usd", + "shares_amount", + "fee", + "side", + "price", + "exchange", + "trade_type" + ], + "properties": { + "trader": { + "type": "string", + "description": "Limit-order maker wallet address (lowercase)" + }, + "taker": { + "type": "string", + "description": "Order filler wallet address (lowercase)" + }, + "position_id": { + "type": "string", + "description": "ERC-1155 outcome token ID" + }, + "condition_id": { + "type": [ + "string", + "null" + ], + "description": "Parent market condition ID" + }, + "outcome": { + "type": [ + "string", + "null" + ], + "description": "Outcome name (e.g. \"Yes\", \"No\")" + }, + "outcome_index": { + "type": [ + "integer", + "null" + ], + "description": "Outcome index: 0 = Yes/Up, 1 = No" + }, + "question": { + "type": [ + "string", + "null" + ], + "description": "Market question text" + }, + "market_slug": { + "type": [ + "string", + "null" + ], + "description": "Market slug" + }, + "event_slug": { + "type": [ + "string", + "null" + ], + "description": "Parent event slug" + }, + "trade_id": { + "type": "string", + "description": "Unique trade identifier" + }, + "hash": { + "type": "string", + "description": "Transaction hash" + }, + "block": { + "type": "integer", + "format": "int64", + "description": "Block number" + }, + "confirmed_at": { + "type": "integer", + "format": "int64", + "description": "Block confirmation timestamp (Unix seconds)" + }, + "amount_usd": { + "type": "number", + "description": "USD size of the trade (6 decimal places)" + }, + "shares_amount": { + "type": "number", + "description": "Outcome shares traded (6 decimal places)" + }, + "fee": { + "type": "number", + "description": "Fee paid in USD (6 decimal places)" + }, + "side": { + "type": "string", + "enum": [ + "Buy", + "Sell" + ], + "description": "Trade direction" + }, + "price": { + "type": "number", + "minimum": 0.0, + "maximum": 1.0, + "description": "Outcome token price (0.0–1.0)" + }, + "probability": { + "type": [ + "number", + "null" + ], + "minimum": 0.0, + "maximum": 1.0, + "description": "Implied probability (0.0–1.0); null when outcome is unknown" + }, + "exchange": { + "type": "string", + "description": "Exchange identifier" + }, + "trade_type": { + "type": "string", + "description": "Trade type identifier" + } + } + }, + "GlobalPnlPayload": { + "type": "object", + "description": "Payload delivered when a trader's global PnL (across all markets) crosses a configured threshold", + "required": [ + "timeframe" + ], + "properties": { + "trader": { + "type": [ + "string", + "null" + ], + "description": "Trader wallet address (lowercase)" + }, + "timeframe": { + "type": "string", + "enum": [ + "1d", + "7d", + "30d", + "lifetime" + ], + "description": "PnL aggregation window" + }, + "realized_pnl_usd": { + "type": [ + "number", + "null" + ], + "description": "Realized PnL in USD (positive = profit, negative = loss)" + }, + "events_traded": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Number of distinct events traded" + }, + "markets_traded": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Number of distinct markets traded" + }, + "total_buys": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Total buy transactions" + }, + "total_sells": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Total sell transactions" + }, + "total_redemptions": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Total redemption transactions" + }, + "total_merges": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Total merge transactions" + }, + "total_volume_usd": { + "type": [ + "number", + "null" + ], + "description": "Total USD volume (buys + sells + redemptions + merges)" + }, + "buy_volume_usd": { + "type": [ + "number", + "null" + ], + "description": "Total buy volume in USD" + }, + "sell_volume_usd": { + "type": [ + "number", + "null" + ], + "description": "Total sell volume in USD" + }, + "redemption_volume_usd": { + "type": [ + "number", + "null" + ], + "description": "Total redemption volume in USD" + }, + "merge_volume_usd": { + "type": [ + "number", + "null" + ], + "description": "Total merge volume in USD" + }, + "markets_won": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Number of markets where trader realised a profit" + }, + "markets_lost": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Number of markets where trader realised a loss" + }, + "market_win_rate_pct": { + "type": [ + "number", + "null" + ], + "description": "Market win rate as a percentage (0.0–100.0)" + }, + "avg_pnl_per_market": { + "type": [ + "number", + "null" + ], + "description": "Average PnL per market in USD" + }, + "avg_pnl_per_trade": { + "type": [ + "number", + "null" + ], + "description": "Average PnL per trade in USD" + }, + "avg_hold_time_seconds": { + "type": [ + "number", + "null" + ], + "description": "Average hold time across all positions (seconds)" + }, + "total_fees": { + "type": [ + "number", + "null" + ], + "description": "Total fees paid in USD" + }, + "best_trade_pnl_usd": { + "type": [ + "number", + "null" + ], + "description": "Best single-trade PnL in USD" + }, + "best_trade_condition_id": { + "type": [ + "string", + "null" + ], + "description": "Condition ID of the best trade" + }, + "first_trade_at": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Timestamp of the first trade (Unix seconds)" + }, + "last_trade_at": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Timestamp of the most recent trade (Unix seconds)" + } + } + }, + "MarketPnlPayload": { + "type": "object", + "description": "Payload delivered when a trader's per-market PnL crosses a configured threshold", + "required": [ + "timeframe" + ], + "properties": { + "trader": { + "type": [ + "string", + "null" + ], + "description": "Trader wallet address (lowercase)" + }, + "condition_id": { + "type": [ + "string", + "null" + ], + "description": "Market condition ID" + }, + "event_slug": { + "type": [ + "string", + "null" + ], + "description": "Parent event slug" + }, + "timeframe": { + "type": "string", + "enum": [ + "1d", + "7d", + "30d", + "lifetime" + ], + "description": "PnL aggregation window" + }, + "outcomes_traded": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Number of distinct outcomes traded in this market" + }, + "total_buys": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "total_sells": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "total_redemptions": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "total_merges": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "buy_usd": { + "type": [ + "number", + "null" + ], + "description": "Total buy volume in USD" + }, + "sell_usd": { + "type": [ + "number", + "null" + ], + "description": "Total sell volume in USD" + }, + "redemption_usd": { + "type": [ + "number", + "null" + ], + "description": "Total redemption volume in USD" + }, + "merge_usd": { + "type": [ + "number", + "null" + ], + "description": "Total merge volume in USD" + }, + "realized_pnl_usd": { + "type": [ + "number", + "null" + ], + "description": "Realized PnL in USD for this market" + }, + "winning_outcomes": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Number of outcomes with positive PnL" + }, + "total_fees": { + "type": [ + "number", + "null" + ], + "description": "Total fees paid in USD for this market" + }, + "first_trade_at": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Timestamp of first trade in market (Unix seconds)" + }, + "last_trade_at": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Timestamp of most recent trade in market (Unix seconds)" + } + } + }, + "EventPnlPayload": { + "type": "object", + "description": "Payload delivered when a trader's per-event PnL crosses a configured threshold", + "required": [ + "timeframe" + ], + "properties": { + "trader": { + "type": [ + "string", + "null" + ], + "description": "Trader wallet address (lowercase)" + }, + "event_slug": { + "type": [ + "string", + "null" + ], + "description": "Event slug" + }, + "timeframe": { + "type": "string", + "enum": [ + "1d", + "7d", + "30d", + "lifetime" + ], + "description": "PnL aggregation window" + }, + "markets_traded": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Number of distinct markets traded in this event" + }, + "outcomes_traded": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "total_buys": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "total_sells": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "total_redemptions": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "total_merges": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "total_volume_usd": { + "type": [ + "number", + "null" + ], + "description": "Total volume in USD" + }, + "buy_usd": { + "type": [ + "number", + "null" + ] + }, + "sell_usd": { + "type": [ + "number", + "null" + ] + }, + "redemption_usd": { + "type": [ + "number", + "null" + ] + }, + "merge_usd": { + "type": [ + "number", + "null" + ] + }, + "realized_pnl_usd": { + "type": [ + "number", + "null" + ], + "description": "Realized PnL in USD for this event" + }, + "winning_markets": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "losing_markets": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "total_fees": { + "type": [ + "number", + "null" + ] + }, + "first_trade_at": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Unix seconds" + }, + "last_trade_at": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Unix seconds" + } + } + }, + "ConditionMetricsPayload": { + "type": "object", + "description": "Payload delivered when a market's volume or transaction metrics cross a configured threshold", + "properties": { + "condition_id": { + "type": [ + "string", + "null" + ], + "description": "Market condition ID" + }, + "timeframe": { + "type": [ + "string", + "null" + ], + "description": "Aggregation window (e.g. \"1h\", \"24h\")" + }, + "volume_usd": { + "type": [ + "number", + "null" + ], + "description": "Total trading volume in USD for this timeframe" + }, + "fees": { + "type": [ + "number", + "null" + ], + "description": "Total fees collected in USD" + }, + "txns": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Total number of transactions" + }, + "unique_traders": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Number of unique traders" + } + } + }, + "EventMetricsPayload": { + "type": "object", + "description": "Payload delivered when an event's aggregated volume or transaction metrics cross a configured threshold", + "properties": { + "event_slug": { + "type": [ + "string", + "null" + ], + "description": "Event slug" + }, + "timeframe": { + "type": [ + "string", + "null" + ], + "description": "Aggregation window (e.g. \"1h\", \"24h\")" + }, + "volume_usd": { + "type": [ + "number", + "null" + ], + "description": "Total aggregated volume across all markets in the event (USD)" + }, + "fees": { + "type": [ + "number", + "null" + ], + "description": "Total fees collected in USD" + }, + "txns": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Total number of transactions" + }, + "unique_traders": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Number of unique traders" + } + } + }, + "PositionMetricsPayload": { + "type": "object", + "description": "Payload delivered when a position's volume or transaction metrics cross a configured threshold", + "properties": { + "position_id": { + "type": [ + "string", + "null" + ], + "description": "ERC-1155 outcome token ID" + }, + "outcome": { + "type": [ + "string", + "null" + ], + "description": "Outcome name (e.g. \"Yes\", \"No\")" + }, + "outcome_index": { + "type": [ + "integer", + "null" + ], + "format": "int16", + "description": "Outcome index" + }, + "timeframe": { + "type": [ + "string", + "null" + ], + "description": "Aggregation window (e.g. \"1h\", \"24h\")" + }, + "volume_usd": { + "type": [ + "number", + "null" + ], + "description": "Total trading volume in USD" + }, + "buy_volume_usd": { + "type": [ + "number", + "null" + ], + "description": "Buy volume in USD" + }, + "sell_volume_usd": { + "type": [ + "number", + "null" + ], + "description": "Sell volume in USD" + }, + "fees": { + "type": [ + "number", + "null" + ], + "description": "Total fees in USD" + }, + "txns": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "buys": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "sells": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "unique_traders": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "price_open": { + "type": [ + "number", + "null" + ], + "minimum": 0.0, + "maximum": 1.0 + }, + "price_close": { + "type": [ + "number", + "null" + ], + "minimum": 0.0, + "maximum": 1.0 + }, + "price_high": { + "type": [ + "number", + "null" + ], + "minimum": 0.0, + "maximum": 1.0 + }, + "price_low": { + "type": [ + "number", + "null" + ], + "minimum": 0.0, + "maximum": 1.0 + }, + "probability_open": { + "type": [ + "number", + "null" + ], + "minimum": 0.0, + "maximum": 1.0 + }, + "probability_close": { + "type": [ + "number", + "null" + ], + "minimum": 0.0, + "maximum": 1.0 + }, + "probability_high": { + "type": [ + "number", + "null" + ], + "minimum": 0.0, + "maximum": 1.0 + }, + "probability_low": { + "type": [ + "number", + "null" + ], + "minimum": 0.0, + "maximum": 1.0 + } + } + }, + "VolumeMilestonePayload": { + "type": "object", + "description": "Payload delivered when a market's trading volume crosses a USD milestone in the specified timeframe", + "required": [ + "condition_id", + "timeframe", + "milestone_usd", + "current_volume_usd", + "fees", + "txns" + ], + "properties": { + "condition_id": { + "type": "string", + "description": "Market condition ID" + }, + "timeframe": { + "type": "string", + "description": "Aggregation window that crossed the milestone (e.g. \"1h\", \"24h\")" + }, + "milestone_usd": { + "type": "number", + "description": "The USD milestone amount that was crossed" + }, + "current_volume_usd": { + "type": "number", + "description": "Current volume at time of trigger (USD)" + }, + "fees": { + "type": "number", + "description": "Total fees in USD for this timeframe" + }, + "txns": { + "type": "integer", + "format": "int64", + "description": "Total transactions in this timeframe" + } + } + }, + "EventVolumeMilestonePayload": { + "type": "object", + "description": "Payload delivered when an event's aggregated trading volume crosses a USD milestone", + "required": [ + "event_slug", + "timeframe", + "milestone_usd", + "current_volume_usd", + "fees", + "txns" + ], + "properties": { + "event_slug": { + "type": "string", + "description": "Event slug" + }, + "timeframe": { + "type": "string", + "description": "Aggregation window (e.g. \"1h\", \"24h\")" + }, + "milestone_usd": { + "type": "number", + "description": "The USD milestone amount that was crossed" + }, + "current_volume_usd": { + "type": "number", + "description": "Current aggregated event volume at time of trigger (USD)" + }, + "fees": { + "type": "number", + "description": "Total fees in USD for this timeframe" + }, + "txns": { + "type": "integer", + "format": "int64", + "description": "Total transactions in this timeframe" + } + } + }, + "PositionVolumeMilestonePayload": { + "type": "object", + "description": "Payload delivered when a position's trading volume crosses a USD milestone", + "required": [ + "position_id", + "timeframe", + "milestone_usd", + "current_volume_usd", + "buy_volume_usd", + "sell_volume_usd", + "fees", + "txns", + "buys", + "sells" + ], + "properties": { + "condition_id": { + "type": [ + "string", + "null" + ], + "description": "Parent market condition ID" + }, + "position_id": { + "type": "string", + "description": "ERC-1155 outcome token ID" + }, + "outcome": { + "type": [ + "string", + "null" + ], + "description": "Outcome name (e.g. \"Yes\", \"No\")" + }, + "outcome_index": { + "type": [ + "integer", + "null" + ], + "format": "int16", + "description": "Outcome index" + }, + "timeframe": { + "type": "string", + "description": "Aggregation window (e.g. \"1h\", \"24h\")" + }, + "milestone_usd": { + "type": "number", + "description": "The USD milestone amount that was crossed" + }, + "current_volume_usd": { + "type": "number", + "description": "Current position volume at time of trigger (USD)" + }, + "buy_volume_usd": { + "type": "number", + "description": "Buy volume in USD for this timeframe" + }, + "sell_volume_usd": { + "type": "number", + "description": "Sell volume in USD for this timeframe" + }, + "fees": { + "type": "number", + "description": "Total fees in USD" + }, + "txns": { + "type": "integer", + "format": "int64" + }, + "buys": { + "type": "integer", + "format": "int64" + }, + "sells": { + "type": "integer", + "format": "int64" + } + } + }, + "ProbabilitySpikePayload": { + "type": "object", + "required": [ + "position_id", + "previous_probability", + "current_probability", + "spike_direction", + "spike_pct" + ], + "properties": { + "position_id": { + "type": "string", + "description": "Outcome token ID" + }, + "condition_id": { + "type": [ + "string", + "null" + ], + "description": "Market condition ID" + }, + "event_slug": { + "type": [ + "string", + "null" + ], + "description": "Event slug" + }, + "outcome": { + "type": [ + "string", + "null" + ], + "description": "Outcome name (e.g. \"Yes\", \"No\")" + }, + "outcome_index": { + "type": [ + "integer", + "null" + ], + "format": "int16", + "description": "Outcome index" + }, + "previous_probability": { + "type": "number", + "description": "Probability at the start of the observation window (baseline snapshot, 0.0–1.0)" + }, + "current_probability": { + "type": "number", + "description": "Current probability that triggered the spike (0.0–1.0)" + }, + "spike_direction": { + "type": "string", + "enum": [ + "up", + "down" + ], + "description": "`\"up\"` = probability rising, `\"down\"` = probability falling" + }, + "spike_pct": { + "type": "number", + "description": "Percentage move that triggered this notification. Positive = up, negative = down." + } + } + }, + "PriceSpikePayload": { + "type": "object", + "required": [ + "position_id", + "previous_price", + "current_price", + "spike_direction", + "spike_pct" + ], + "properties": { + "position_id": { + "type": "string", + "description": "Outcome token ID" + }, + "condition_id": { + "type": [ + "string", + "null" + ], + "description": "Market condition ID" + }, + "event_slug": { + "type": [ + "string", + "null" + ], + "description": "Event slug" + }, + "outcome": { + "type": [ + "string", + "null" + ], + "description": "Outcome name (e.g. \"Yes\", \"No\")" + }, + "outcome_index": { + "type": [ + "integer", + "null" + ], + "format": "int16", + "description": "Outcome index" + }, + "previous_price": { + "type": "number", + "description": "Price at the start of the observation window (baseline snapshot, 0.0–1.0)" + }, + "current_price": { + "type": "number", + "description": "Current price that triggered the spike (0.0–1.0)" + }, + "spike_direction": { + "type": "string", + "enum": [ + "up", + "down" + ], + "description": "`\"up\"` = price rising, `\"down\"` = price falling" + }, + "spike_pct": { + "type": "number", + "description": "Percentage move that triggered this notification. Positive = up, negative = down." + } + } + }, + "MarketVolumeSpikePayload": { + "type": "object", + "description": "Payload delivered when a market's volume has spiked since the last snapshot", + "required": [ + "condition_id", + "timeframe", + "current_volume_usd", + "snapshot_volume_usd", + "delta_volume_usd", + "spike_pct", + "txns", + "fees" + ], + "properties": { + "condition_id": { + "type": "string", + "description": "Market condition ID" + }, + "timeframe": { + "type": "string", + "description": "Aggregation window (e.g. \"1h\", \"24h\")" + }, + "current_volume_usd": { + "type": "number", + "description": "Current volume at the time of the spike (USD)" + }, + "snapshot_volume_usd": { + "type": "number", + "description": "Volume at the snapshot baseline (USD)" + }, + "delta_volume_usd": { + "type": "number", + "description": "New volume since the snapshot that triggered this notification (USD)" + }, + "spike_pct": { + "type": "number", + "description": "Volume growth as a percentage of the snapshot (e.g. 200.0 means volume tripled)" + }, + "txns": { + "type": "integer", + "format": "int64", + "description": "Total transactions in this timeframe" + }, + "fees": { + "type": "number", + "description": "Total fees in USD for this timeframe" + } + } + }, + "EventVolumeSpikePayload": { + "type": "object", + "description": "Payload delivered when an event's aggregated volume has spiked since the last snapshot", + "required": [ + "event_slug", + "timeframe", + "current_volume_usd", + "snapshot_volume_usd", + "delta_volume_usd", + "spike_pct", + "txns", + "fees" + ], + "properties": { + "event_slug": { + "type": "string", + "description": "Event slug" + }, + "timeframe": { + "type": "string", + "description": "Aggregation window (e.g. \"1h\", \"24h\")" + }, + "current_volume_usd": { + "type": "number", + "description": "Current aggregated event volume at time of the spike (USD)" + }, + "snapshot_volume_usd": { + "type": "number", + "description": "Volume at the snapshot baseline (USD)" + }, + "delta_volume_usd": { + "type": "number", + "description": "New volume since the snapshot that triggered this notification (USD)" + }, + "spike_pct": { + "type": "number", + "description": "Volume growth as a percentage of the snapshot (e.g. 200.0 means volume tripled)" + }, + "txns": { + "type": "integer", + "format": "int64" + }, + "fees": { + "type": "number" + } + } + }, + "PositionVolumeSpikePayload": { + "type": "object", + "description": "Payload delivered when a position's volume has spiked since the last snapshot", + "required": [ + "position_id", + "condition_id", + "timeframe", + "current_volume_usd", + "snapshot_volume_usd", + "delta_volume_usd", + "spike_pct", + "txns", + "fees" + ], + "properties": { + "position_id": { + "type": "string", + "description": "ERC-1155 outcome token ID" + }, + "condition_id": { + "type": "string", + "description": "Parent market condition ID" + }, + "outcome": { + "type": [ + "string", + "null" + ], + "description": "Outcome name (e.g. \"Yes\", \"No\")" + }, + "outcome_index": { + "type": [ + "integer", + "null" + ], + "format": "int16" + }, + "timeframe": { + "type": "string", + "description": "Aggregation window (e.g. \"1h\", \"24h\")" + }, + "current_volume_usd": { + "type": "number", + "description": "Current position volume at the time of the spike (USD)" + }, + "snapshot_volume_usd": { + "type": "number", + "description": "Volume at the snapshot baseline (USD)" + }, + "delta_volume_usd": { + "type": "number", + "description": "New volume since the snapshot that triggered this notification (USD)" + }, + "spike_pct": { + "type": "number", + "description": "Volume growth as a percentage of the snapshot (e.g. 200.0 means volume tripled)" + }, + "txns": { + "type": "integer", + "format": "int64" + }, + "fees": { + "type": "number" + } + } + }, + "CloseToBondPayload": { + "type": "object", + "description": "Payload delivered when a trade occurs at a near-certain-outcome price", + "required": [ + "trader", + "taker", + "position_id", + "trade_id", + "hash", + "block", + "confirmed_at", + "amount_usd", + "shares_amount", + "fee", + "side", + "price", + "bond_side", + "threshold" + ], + "properties": { + "trader": { + "type": "string", + "description": "Limit-order maker wallet address (lowercase)" + }, + "taker": { + "type": "string", + "description": "Order filler wallet address (lowercase)" + }, + "position_id": { + "type": "string", + "description": "ERC-1155 outcome token ID" + }, + "condition_id": { + "type": [ + "string", + "null" + ], + "description": "Parent market condition ID" + }, + "outcome": { + "type": [ + "string", + "null" + ], + "description": "Outcome name (e.g. \"Yes\", \"No\")" + }, + "outcome_index": { + "type": [ + "integer", + "null" + ], + "description": "0 = Yes/Up, 1 = No" + }, + "question": { + "type": [ + "string", + "null" + ] + }, + "market_slug": { + "type": [ + "string", + "null" + ] + }, + "event_slug": { + "type": [ + "string", + "null" + ] + }, + "trade_id": { + "type": "string" + }, + "hash": { + "type": "string", + "description": "Transaction hash" + }, + "block": { + "type": "integer", + "format": "int64" + }, + "confirmed_at": { + "type": "integer", + "format": "int64", + "description": "Unix seconds" + }, + "amount_usd": { + "type": "number", + "description": "USD size of the trade" + }, + "shares_amount": { + "type": "number" + }, + "fee": { + "type": "number", + "description": "Fee paid in USD" + }, + "side": { + "type": "string", + "enum": [ + "Buy", + "Sell" + ] + }, + "price": { + "type": "number", + "minimum": 0.0, + "maximum": 1.0, + "description": "Price that triggered the notification (0.0–1.0)" + }, + "probability": { + "type": [ + "number", + "null" + ], + "minimum": 0.0, + "maximum": 1.0, + "description": "Implied probability (0.0–1.0)" + }, + "bond_side": { + "type": "string", + "enum": [ + "high", + "low" + ], + "description": "\"high\" when near YES (price ≥ threshold), \"low\" when near NO (price ≤ threshold)" + }, + "threshold": { + "type": "number", + "description": "The probability threshold from the subscription filter that was breached" + } + } + }, + "MarketCreatedOutcome": { + "type": "object", + "description": "An outcome entry within a newly created market", + "required": [ + "index", + "name", + "position_id" + ], + "properties": { + "index": { + "type": "integer", + "description": "Outcome index (0 = Yes, 1 = No)" + }, + "name": { + "type": "string", + "description": "Outcome name (e.g. \"Yes\", \"No\")" + }, + "position_id": { + "type": "string", + "description": "ERC-1155 position token ID for this outcome" + } + } + }, + "MarketCreatedPayload": { + "type": "object", + "description": "Payload delivered when a new prediction market is detected on-chain and enriched with Gamma API metadata", + "required": [ + "condition_id", + "market_slug", + "outcomes", + "question", + "description", + "tags", + "neg_risk" + ], + "properties": { + "condition_id": { + "type": "string", + "description": "Condition ID (0x-prefixed hex, lowercase)" + }, + "market_slug": { + "type": "string", + "description": "Market slug" + }, + "event_slug": { + "type": [ + "string", + "null" + ], + "description": "Parent event slug" + }, + "event_id": { + "type": [ + "string", + "null" + ], + "description": "Parent event ID" + }, + "event_title": { + "type": [ + "string", + "null" + ], + "description": "Parent event title" + }, + "series_slug": { + "type": [ + "string", + "null" + ], + "description": "Series slug (for recurring markets)" + }, + "outcomes": { + "type": "array", + "description": "List of market outcomes with their position IDs", + "items": { + "$ref": "#/components/schemas/MarketCreatedOutcome" + } + }, + "question": { + "type": "string", + "description": "Full market question text" + }, + "title": { + "type": [ + "string", + "null" + ], + "description": "Short display title" + }, + "description": { + "type": "string", + "description": "Market description" + }, + "category": { + "type": [ + "string", + "null" + ], + "description": "Market category (e.g. \"Sports\", \"Politics\")" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Market tags" + }, + "image_url": { + "type": [ + "string", + "null" + ], + "description": "Cover image URL" + }, + "neg_risk": { + "type": "boolean", + "description": "Whether this is a neg-risk market" + } + } + }, + "AssetPriceTickPayload": { + "type": "object", + "description": "Payload delivered on every raw Chainlink price tick for a tracked crypto asset", + "required": [ + "symbol", + "price", + "timestamp_ms" + ], + "properties": { + "symbol": { + "type": "string", + "enum": [ + "BTC", + "ETH", + "SOL", + "XRP", + "DOGE", + "BNB", + "HYPE" + ], + "description": "Asset symbol" + }, + "price": { + "type": "number", + "description": "Current asset price in USD from the Chainlink feed" + }, + "timestamp_ms": { + "type": "integer", + "format": "int64", + "description": "Tick timestamp (milliseconds since Unix epoch)" + } + } + }, + "AssetPriceWindowUpdatePayload": { + "type": "object", + "description": "Payload delivered twice per candle — once on open and once on close. `close_price` is 0.0 on the \"open\" update.", + "required": [ + "symbol", + "variant", + "start_time", + "end_time", + "open_price", + "close_price", + "update_type" + ], + "properties": { + "symbol": { + "type": "string", + "enum": [ + "BTC", + "ETH", + "SOL", + "XRP", + "DOGE", + "BNB", + "HYPE" + ], + "description": "Asset symbol" + }, + "variant": { + "type": "string", + "enum": [ + "5m", + "15m", + "1h", + "4h", + "1d", + "24h" + ], + "description": "Candle / window size" + }, + "start_time": { + "type": "integer", + "format": "int64", + "description": "Window start timestamp (milliseconds since Unix epoch)" + }, + "end_time": { + "type": "integer", + "format": "int64", + "description": "Window end timestamp (milliseconds since Unix epoch)" + }, + "open_price": { + "type": "number", + "description": "Opening price at start_time (USD)" + }, + "close_price": { + "type": "number", + "description": "Closing price at end_time (USD). 0.0 when update_type is \"open\" (not yet available)." + }, + "update_type": { + "type": "string", + "enum": [ + "open", + "close" + ], + "description": "\"open\" when the candle opens, \"close\" when it closes with a confirmed price" + } + } + }, + "TraderFirstTradeFilters": { + "type": "object", + "description": "Subscription filters for the `trader_first_trade` event. All fields are optional.", + "properties": { + "wallet_addresses": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Only fire for trades by these wallet addresses (lowercase). Empty = all traders." + }, + "condition_ids": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to trades in these markets. Empty = all markets." + }, + "event_slugs": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to trades in markets belonging to these events." + }, + "min_usd_value": { + "type": "number", + "description": "Minimum trade size in USD. Omit to match all sizes." + }, + "min_probability": { + "type": "number", + "minimum": 0.0, + "maximum": 1.0, + "description": "Only fire when the outcome probability is ≥ this value." + }, + "max_probability": { + "type": "number", + "minimum": 0.0, + "maximum": 1.0, + "description": "Only fire when the outcome probability is ≤ this value." + }, + "exclude_shortterm_markets": { + "type": "boolean", + "description": "When `true`, suppress webhooks for short-term \"updown\" markets (event slugs containing `updown`). Default: `false`." + } + } + }, + "TraderNewMarketFilters": { + "type": "object", + "description": "Subscription filters for the `trader_new_market` event. All fields are optional.", + "properties": { + "wallet_addresses": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Only fire for these wallet addresses (lowercase). Empty = all traders." + }, + "condition_ids": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to these markets." + }, + "event_slugs": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to markets belonging to these events." + }, + "exclude_shortterm_markets": { + "type": "boolean", + "description": "When `true`, suppress webhooks for short-term \"updown\" markets. Default: `false`." + } + } + }, + "TraderWhaleTradeFilters": { + "type": "object", + "description": "Subscription filters for the `trader_whale_trade` event. All fields are optional.", + "properties": { + "wallet_addresses": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Only fire for trades by these wallet addresses. Empty = all traders." + }, + "condition_ids": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to these markets." + }, + "event_slugs": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to markets belonging to these events." + }, + "min_usd_value": { + "type": "number", + "default": 0, + "description": "Minimum trade size in USD. Defaults to 0 (matches all trades)." + }, + "min_probability": { + "type": "number", + "minimum": 0.0, + "maximum": 1.0, + "description": "Only fire when outcome probability is ≥ this value." + }, + "max_probability": { + "type": "number", + "minimum": 0.0, + "maximum": 1.0, + "description": "Only fire when outcome probability is ≤ this value." + }, + "exclude_shortterm_markets": { + "type": "boolean", + "description": "When `true`, suppress webhooks for short-term \"updown\" markets. Default: `false`." + } + } + }, + "TraderNewTradeFilters": { + "type": "object", + "description": "Subscription filters for the `trader_new_trade` event. All fields are optional.", + "properties": { + "wallet_addresses": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Only fire for trades by these wallet addresses. Empty = all traders." + }, + "condition_ids": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to these markets." + }, + "event_slugs": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to markets belonging to these events." + }, + "min_usd_value": { + "type": "number", + "default": 0, + "description": "Minimum trade size in USD. Defaults to 0 (matches all trades)." + }, + "min_probability": { + "type": "number", + "minimum": 0.0, + "maximum": 1.0, + "description": "Only fire when outcome probability is ≥ this value." + }, + "max_probability": { + "type": "number", + "minimum": 0.0, + "maximum": 1.0, + "description": "Only fire when outcome probability is ≤ this value." + }, + "exclude_shortterm_markets": { + "type": "boolean", + "description": "When `true`, suppress webhooks for short-term \"updown\" markets. Default: `false`." + } + } + }, + "TraderGlobalPnlFilters": { + "type": "object", + "description": "Subscription filters for the `trader_global_pnl` event. All fields are optional.", + "properties": { + "traders": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Track only these trader wallet addresses. Empty = all traders." + }, + "min_realized_pnl_usd": { + "type": "number", + "description": "Only fire when realized PnL ≥ this value (USD). Use negative values for loss thresholds." + }, + "max_realized_pnl_usd": { + "type": "number", + "description": "Only fire when realized PnL ≤ this value (USD)." + }, + "min_volume_usd": { + "type": "number", + "description": "Only fire when total trading volume ≥ this value (USD)." + }, + "max_volume_usd": { + "type": "number", + "description": "Only fire when total trading volume ≤ this value (USD)." + }, + "min_buy_usd": { + "type": "number", + "description": "Only fire when buy volume ≥ this value (USD)." + }, + "min_sell_volume_usd": { + "type": "number", + "description": "Only fire when sell volume ≥ this value (USD)." + }, + "min_win_rate": { + "type": "number", + "minimum": 0.0, + "maximum": 100.0, + "description": "Only fire when market win rate ≥ this percentage (0.0–100.0)." + }, + "min_markets_traded": { + "type": "integer", + "format": "int64", + "description": "Only fire when the trader has traded in ≥ this many markets." + }, + "timeframes": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "1d", + "7d", + "30d", + "lifetime" + ] + }, + "description": "Restrict to these PnL windows. Empty = all windows." + } + } + }, + "TraderMarketPnlFilters": { + "type": "object", + "description": "Subscription filters for the `trader_market_pnl` event. All fields are optional.", + "properties": { + "traders": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Track only these trader wallet addresses." + }, + "condition_ids": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to these markets." + }, + "event_slugs": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to markets in these events." + }, + "min_realized_pnl_usd": { + "type": "number", + "description": "Only fire when per-market realized PnL ≥ this value (USD)." + }, + "max_realized_pnl_usd": { + "type": "number", + "description": "Only fire when per-market realized PnL ≤ this value (USD)." + }, + "min_volume_usd": { + "type": "number", + "description": "Only fire when total volume (buy + sell + redemption + merge) ≥ this value (USD)." + }, + "max_volume_usd": { + "type": "number", + "description": "Only fire when total volume ≤ this value (USD)." + }, + "min_buy_usd": { + "type": "number", + "description": "Only fire when buy volume in the market ≥ this value (USD)." + }, + "min_sell_volume_usd": { + "type": "number", + "description": "Only fire when sell volume in the market ≥ this value (USD)." + }, + "timeframes": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "1d", + "7d", + "30d", + "lifetime" + ] + }, + "description": "Restrict to these PnL windows." + }, + "exclude_shortterm_markets": { + "type": "boolean", + "description": "When `true`, suppress webhooks for short-term \"updown\" markets. Default: `false`." + } + } + }, + "TraderEventPnlFilters": { + "type": "object", + "description": "Subscription filters for the `trader_event_pnl` event. All fields are optional.", + "properties": { + "traders": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Track only these trader wallet addresses." + }, + "event_slugs": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to these events." + }, + "min_realized_pnl_usd": { + "type": "number", + "description": "Only fire when per-event realized PnL ≥ this value (USD)." + }, + "max_realized_pnl_usd": { + "type": "number", + "description": "Only fire when per-event realized PnL ≤ this value (USD)." + }, + "min_volume_usd": { + "type": "number", + "description": "Only fire when total event volume ≥ this value (USD)." + }, + "max_volume_usd": { + "type": "number", + "description": "Only fire when total event volume ≤ this value (USD)." + }, + "min_buy_usd": { + "type": "number", + "description": "Only fire when buy volume within the event ≥ this value (USD)." + }, + "min_sell_volume_usd": { + "type": "number", + "description": "Only fire when sell volume within the event ≥ this value (USD)." + }, + "min_markets_traded": { + "type": "integer", + "format": "int64", + "description": "Only fire when the trader has traded in ≥ this many markets within the event." + }, + "timeframes": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "1d", + "7d", + "30d", + "lifetime" + ] + }, + "description": "Restrict to these PnL windows." + }, + "exclude_shortterm_markets": { + "type": "boolean", + "description": "When `true`, suppress webhooks for short-term \"updown\" markets. Default: `false`." + } + } + }, + "MarketMetricsFilters": { + "type": "object", + "description": "Subscription filters for the `condition_metrics` event. All fields are optional.", + "properties": { + "condition_ids": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to these markets. Empty = all markets." + }, + "event_slugs": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to markets in these events." + }, + "timeframes": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "1m", + "5m", + "30m", + "1h", + "6h", + "24h", + "7d", + "30d" + ] + }, + "maxItems": 500, + "description": "Restrict to these aggregation windows. Empty = all windows." + }, + "min_volume_usd": { + "type": "number", + "description": "Only fire when volume ≥ this value (USD)." + }, + "max_volume_usd": { + "type": "number", + "description": "Only fire when volume ≤ this value (USD)." + }, + "min_txns": { + "type": "integer", + "format": "int64", + "description": "Only fire when transaction count ≥ this value." + }, + "min_unique_traders": { + "type": "integer", + "format": "int64", + "description": "Only fire when unique trader count ≥ this value." + }, + "min_fees": { + "type": "number", + "description": "Only fire when total fees ≥ this value (USD)." + } + } + }, + "EventMetricsFilters": { + "type": "object", + "description": "Subscription filters for the `event_metrics` event. All fields are optional.", + "properties": { + "event_slugs": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to these events. Empty = all events." + }, + "timeframes": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "1m", + "5m", + "30m", + "1h", + "6h", + "24h", + "7d", + "30d" + ] + }, + "maxItems": 500, + "description": "Restrict to these aggregation windows." + }, + "min_volume_usd": { + "type": "number", + "description": "Only fire when aggregated event volume ≥ this value (USD)." + }, + "max_volume_usd": { + "type": "number" + }, + "min_txns": { + "type": "integer", + "format": "int64" + }, + "min_unique_traders": { + "type": "integer", + "format": "int64" + }, + "min_fees": { + "type": "number" + }, + "exclude_shortterm_markets": { + "type": "boolean", + "description": "When `true`, suppress webhooks for short-term \"updown\" markets. Default: `false`." + } + } + }, + "PositionMetricsFilters": { + "type": "object", + "description": "Subscription filters for the `position_metrics` event. All fields are optional.", + "properties": { + "position_ids": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to these outcome token IDs." + }, + "condition_ids": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to positions within these markets." + }, + "outcomes": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to positions with these outcome names (e.g. [\"Yes\", \"No\"])." + }, + "timeframes": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "1m", + "5m", + "30m", + "1h", + "6h", + "24h", + "7d", + "30d" + ] + }, + "maxItems": 500, + "description": "Restrict to these aggregation windows." + }, + "min_volume_usd": { + "type": "number", + "description": "Only fire when position volume ≥ this value (USD)." + }, + "max_volume_usd": { + "type": "number" + }, + "min_buy_usd": { + "type": "number" + }, + "min_sell_volume_usd": { + "type": "number" + }, + "min_txns": { + "type": "integer", + "format": "int64" + }, + "min_unique_traders": { + "type": "integer", + "format": "int64" + }, + "min_price_change_pct": { + "type": "number", + "description": "Only fire when price change % ≥ this value." + }, + "min_probability_change_pct": { + "type": "number", + "description": "Only fire when probability change % ≥ this value." + }, + "min_fees": { + "type": "number" + } + } + }, + "MarketVolumeMilestoneFilters": { + "type": "object", + "description": "Subscription filters for the `market_volume_milestone` event.", + "required": [ + "timeframes" + ], + "properties": { + "timeframes": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "1m", + "5m", + "30m", + "1h", + "6h", + "24h", + "7d", + "30d" + ] + }, + "minItems": 1, + "maxItems": 500, + "description": "**Required.** Aggregation windows to monitor (e.g. [\"1h\", \"24h\"])." + }, + "condition_ids": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to these markets. Empty = all markets." + }, + "milestone_amounts": { + "type": "array", + "items": { + "type": "integer", + "format": "int64" + }, + "maxItems": 500, + "description": "Specific USD milestones to trigger on (e.g. [10000, 100000, 1000000]). Empty = all milestones." + } + } + }, + "EventVolumeMilestoneFilters": { + "type": "object", + "description": "Subscription filters for the `event_volume_milestone` event.", + "required": [ + "timeframes" + ], + "properties": { + "timeframes": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "1m", + "5m", + "30m", + "1h", + "6h", + "24h", + "7d", + "30d" + ] + }, + "minItems": 1, + "maxItems": 500, + "description": "**Required.** Aggregation windows to monitor." + }, + "event_slugs": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to these events." + }, + "milestone_amounts": { + "type": "array", + "items": { + "type": "integer", + "format": "int64" + }, + "maxItems": 500, + "description": "Specific USD milestones to trigger on." + }, + "exclude_shortterm_markets": { + "type": "boolean", + "description": "When `true`, suppress webhooks for short-term \"updown\" markets. Default: `false`." + } + } + }, + "PositionVolumeMilestoneFilters": { + "type": "object", + "description": "Subscription filters for the `position_volume_milestone` event.", + "required": [ + "timeframes" + ], + "properties": { + "timeframes": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "1m", + "5m", + "30m", + "1h", + "6h", + "24h", + "7d", + "30d" + ] + }, + "minItems": 1, + "maxItems": 500, + "description": "**Required.** Aggregation windows to monitor." + }, + "position_ids": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to these outcome token IDs." + }, + "condition_ids": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to positions within these markets." + }, + "milestone_amounts": { + "type": "array", + "items": { + "type": "integer", + "format": "int64" + }, + "maxItems": 500, + "description": "Specific USD milestones to trigger on." + } + } + }, + "ProbabilitySpikeFilters": { + "type": "object", + "description": "Subscription filters for the `probability_spike` event.", + "properties": { + "position_ids": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to specific outcome token IDs. Empty = all positions." + }, + "condition_ids": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to specific market condition IDs. Empty = all markets." + }, + "event_slugs": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to specific events. Empty = all events." + }, + "outcomes": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to these outcome names (e.g. [\"Yes\", \"No\"])." + }, + "min_probability_change_pct": { + "type": "number", + "description": "Minimum probability percentage move to trigger (e.g. `10` for a 10% move)." + }, + "spike_direction": { + "type": "string", + "enum": [ + "up", + "down", + "both" + ], + "description": "`\"up\"` = probability rising only (default when omitted), `\"down\"` = falling only, `\"both\"` = either direction." + }, + "window_secs": { + "type": "integer", + "minimum": 1, + "maximum": 600, + "description": "Observation window in seconds. The first trade in each window sets the reference price; subsequent trades are compared to it. E.g. `60` detects moves that occur within 60 seconds." + }, + "exclude_shortterm_markets": { + "type": "boolean", + "description": "When `true`, suppress webhooks for short-term \"updown\" markets. Default: `false`." + } + } + }, + "PriceSpikeFilters": { + "type": "object", + "description": "Subscription filters for the `price_spike` event.", + "properties": { + "position_ids": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to specific outcome token IDs. Empty = all positions." + }, + "condition_ids": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to specific market condition IDs. Empty = all markets." + }, + "event_slugs": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to specific events. Empty = all events." + }, + "outcomes": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to these outcome names (e.g. [\"Yes\", \"No\"])." + }, + "min_price_change_pct": { + "type": "number", + "description": "Minimum price percentage move to trigger (e.g. `10` for a 10% move)." + }, + "spike_direction": { + "type": "string", + "enum": [ + "up", + "down", + "both" + ], + "description": "`\"up\"` = price rising only (default when omitted), `\"down\"` = falling only, `\"both\"` = either direction." + }, + "window_secs": { + "type": "integer", + "minimum": 1, + "maximum": 600, + "description": "Observation window in seconds. The first trade in each window sets the reference price; subsequent trades are compared to it. E.g. `60` detects moves that occur within 60 seconds." + }, + "exclude_shortterm_markets": { + "type": "boolean", + "description": "When `true`, suppress webhooks for short-term \"updown\" markets. Default: `false`." + } + } + }, + "MarketVolumeSpikeFilters": { + "type": "object", + "description": "Subscription filters for the `market_volume_spike` event. `spike_ratio` is required.", + "required": [ + "spike_ratio" + ], + "properties": { + "spike_ratio": { + "type": "number", + "exclusiveMinimum": 1.0, + "description": "**Required.** Multiplier threshold (must be > 1.0). Fires when current volume >= snapshot × ratio. The snapshot is set automatically on first data and resets after each fire." + }, + "window_secs": { + "type": "integer", + "minimum": 1, + "maximum": 600, + "description": "Force snapshot reset after this many seconds (max 600 / 10 minutes)." + }, + "condition_ids": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to these markets. Empty = all markets." + }, + "timeframes": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "1m", + "5m", + "30m", + "1h", + "6h", + "1d", + "24h", + "7d", + "30d" + ] + }, + "maxItems": 500, + "description": "Restrict to these aggregation windows. Empty = all windows." + } + } + }, + "EventVolumeSpikeFilters": { + "type": "object", + "description": "Subscription filters for the `event_volume_spike` event. `spike_ratio` is required.", + "required": [ + "spike_ratio" + ], + "properties": { + "spike_ratio": { + "type": "number", + "exclusiveMinimum": 1.0, + "description": "**Required.** Multiplier threshold (must be > 1.0). Fires when current volume >= snapshot × ratio." + }, + "window_secs": { + "type": "integer", + "minimum": 1, + "maximum": 600, + "description": "Force snapshot reset after this many seconds (max 600 / 10 minutes)." + }, + "event_slugs": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to these events." + }, + "timeframes": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "1m", + "5m", + "30m", + "1h", + "6h", + "1d", + "24h", + "7d", + "30d" + ] + }, + "maxItems": 500, + "description": "Restrict to these aggregation windows." + }, + "exclude_shortterm_markets": { + "type": "boolean", + "description": "When `true`, suppress webhooks for short-term \"updown\" markets. Default: `false`." + } + } + }, + "WsAlertEventType": { + "type": "string", + "description": "All alert event types supported by both HTTP webhooks and the alerts WebSocket.", + "enum": [ + "trader_first_trade", + "trader_new_market", + "trader_whale_trade", + "trader_new_trade", + "trader_global_pnl", + "trader_market_pnl", + "trader_event_pnl", + "condition_metrics", + "event_metrics", + "position_metrics", + "market_volume_milestone", + "event_volume_milestone", + "position_volume_milestone", + "probability_spike", + "price_spike", + "market_volume_spike", + "event_volume_spike", + "position_volume_spike", + "close_to_bond", + "market_created", + "asset_price_tick", + "asset_price_window_update" + ] + }, + "WsAlertSubscribedResponse": { + "type": "object", + "required": [ + "op", + "event", + "subscription_id" + ], + "description": "Server acknowledgement for a successful alert subscription.", + "properties": { + "op": { + "type": "string", + "enum": [ + "subscribed" + ] + }, + "event": { + "$ref": "#/components/schemas/WsAlertEventType" + }, + "subscription_id": { + "type": "string", + "format": "uuid" + } + } + }, + "WsAlertUnsubscribedResponse": { + "type": "object", + "required": [ + "op", + "event" + ], + "description": "Server acknowledgement for a successful alert unsubscription.", + "properties": { + "op": { + "type": "string", + "enum": [ + "unsubscribed" + ] + }, + "event": { + "$ref": "#/components/schemas/WsAlertEventType" + } + } + }, + "WsAlertErrorResponse": { + "type": "object", + "required": [ + "error" + ], + "description": "Error returned by the alerts WebSocket when a message is invalid or a subscription request fails.", + "properties": { + "error": { + "type": "string" + } + } + }, + "WsAlertTraderFirstTradeSubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Subscribe to `trader_first_trade` alerts. Fired when a tracked trader executes their first trade on Polymarket", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "subscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "trader_first_trade" + ] + } + }, + "example": { + "op": "subscribe", + "event": "trader_first_trade", + "wallet_addresses": [ + "0x0000000000000000000000000000000000000000" + ], + "min_usd_value": 10000.0, + "min_probability": 0.95, + "max_probability": 0.05, + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "event_slugs": [ + "example-event" + ], + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/TraderFirstTradeFilters" + } + ] + }, + "WsAlertTraderFirstTradeUnsubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Unsubscribe from `trader_first_trade` alerts. The filter fields must match the original subscription exactly.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "unsubscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "trader_first_trade" + ] + } + }, + "example": { + "op": "unsubscribe", + "event": "trader_first_trade", + "wallet_addresses": [ + "0x0000000000000000000000000000000000000000" + ], + "min_usd_value": 10000.0, + "min_probability": 0.95, + "max_probability": 0.05, + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "event_slugs": [ + "example-event" + ], + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/TraderFirstTradeFilters" + } + ] + }, + "WsAlertTraderFirstTradeEvent": { + "type": "object", + "required": [ + "event", + "timestamp", + "data" + ], + "description": "Pushed `trader_first_trade` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "properties": { + "event": { + "type": "string", + "enum": [ + "trader_first_trade" + ] + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix timestamp in milliseconds" + }, + "data": { + "$ref": "#/components/schemas/FirstTradePayload" + } + }, + "example": { + "event": "trader_first_trade", + "timestamp": 1743500000000, + "data": { + "trader": "0x0000000000000000000000000000000000000000", + "taker": "0x0000000000000000000000000000000000000000", + "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", + "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + "outcome": "Yes", + "outcome_index": 0, + "question": "Will this test webhook fire correctly?", + "market_slug": "test-market-0000000000", + "event_slug": "test-event-0000000000", + "trade_id": "00000000-0000-0000-0000-000000000000", + "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "block": 0, + "confirmed_at": 1700000000, + "amount_usd": 125.0, + "shares_amount": 250.0, + "fee": 0.125, + "side": "Buy", + "price": 0.5, + "exchange": "polymarket", + "trade_type": "OrderFilled" + } + } + }, + "WsAlertTraderNewMarketSubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Subscribe to `trader_new_market` alerts. Fired when a trader places their first trade in a specific market/condition (fires once per trader+market pair)", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "subscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "trader_new_market" + ] + } + }, + "example": { + "op": "subscribe", + "event": "trader_new_market", + "wallet_addresses": [ + "0x0000000000000000000000000000000000000000" + ], + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "event_slugs": [ + "example-event" + ], + "min_usd_value": 10000.0, + "min_probability": 0.95, + "max_probability": 0.05, + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/TraderNewMarketFilters" + } + ] + }, + "WsAlertTraderNewMarketUnsubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Unsubscribe from `trader_new_market` alerts. The filter fields must match the original subscription exactly.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "unsubscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "trader_new_market" + ] + } + }, + "example": { + "op": "unsubscribe", + "event": "trader_new_market", + "wallet_addresses": [ + "0x0000000000000000000000000000000000000000" + ], + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "event_slugs": [ + "example-event" + ], + "min_usd_value": 10000.0, + "min_probability": 0.95, + "max_probability": 0.05, + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/TraderNewMarketFilters" + } + ] + }, + "WsAlertTraderNewMarketEvent": { + "type": "object", + "required": [ + "event", + "timestamp", + "data" + ], + "description": "Pushed `trader_new_market` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "properties": { + "event": { + "type": "string", + "enum": [ + "trader_new_market" + ] + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix timestamp in milliseconds" + }, + "data": { + "$ref": "#/components/schemas/NewMarketPayload" + } + }, + "example": { + "event": "trader_new_market", + "timestamp": 1743500000000, + "data": { + "trader": "0x0000000000000000000000000000000000000000", + "taker": "0x0000000000000000000000000000000000000000", + "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", + "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + "outcome": "Yes", + "outcome_index": 0, + "question": "Will this test webhook fire correctly?", + "market_slug": "test-market-0000000000", + "event_slug": "test-event-0000000000", + "trade_id": "00000000-0000-0000-0000-000000000000", + "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "block": 0, + "confirmed_at": 1700000000, + "amount_usd": 125.0, + "shares_amount": 250.0, + "fee": 0.125, + "side": "Buy", + "price": 0.5, + "probability": 0.5, + "exchange": "polymarket", + "trade_type": "OrderFilled" + } + } + }, + "WsAlertTraderWhaleTradeSubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Subscribe to `trader_whale_trade` alerts. Fired when a trade meets the configured criteria. Use `min_usd_value` to filter by minimum trade size (optional, defaults to 0 — matches all trades), and `min_probability`/`max_probability` to restrict to a probability range.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "subscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "trader_whale_trade" + ] + } + }, + "example": { + "op": "subscribe", + "event": "trader_whale_trade", + "wallet_addresses": [ + "0x0000000000000000000000000000000000000000" + ], + "min_usd_value": 10000.0, + "min_probability": 0.95, + "max_probability": 0.05, + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "event_slugs": [ + "example-event" + ], + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/TraderWhaleTradeFilters" + } + ] + }, + "WsAlertTraderWhaleTradeUnsubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Unsubscribe from `trader_whale_trade` alerts. The filter fields must match the original subscription exactly.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "unsubscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "trader_whale_trade" + ] + } + }, + "example": { + "op": "unsubscribe", + "event": "trader_whale_trade", + "wallet_addresses": [ + "0x0000000000000000000000000000000000000000" + ], + "min_usd_value": 10000.0, + "min_probability": 0.95, + "max_probability": 0.05, + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "event_slugs": [ + "example-event" + ], + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/TraderWhaleTradeFilters" + } + ] + }, + "WsAlertTraderWhaleTradeEvent": { + "type": "object", + "required": [ + "event", + "timestamp", + "data" + ], + "description": "Pushed `trader_whale_trade` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "properties": { + "event": { + "type": "string", + "enum": [ + "trader_whale_trade" + ] + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix timestamp in milliseconds" + }, + "data": { + "$ref": "#/components/schemas/WhaleTradePayload" + } + }, + "example": { + "event": "trader_whale_trade", + "timestamp": 1743500000000, + "data": { + "trader": "0x0000000000000000000000000000000000000000", + "taker": "0x0000000000000000000000000000000000000000", + "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", + "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + "outcome": "Yes", + "outcome_index": 0, + "question": "Will this test webhook fire correctly?", + "market_slug": "test-market-0000000000", + "event_slug": "test-event-0000000000", + "trade_id": "00000000-0000-0000-0000-000000000000", + "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "block": 0, + "confirmed_at": 1700000000, + "amount_usd": 125.0, + "shares_amount": 250.0, + "fee": 0.125, + "side": "Buy", + "price": 0.5, + "probability": 0.5, + "exchange": "polymarket", + "trade_type": "OrderFilled" + } + } + }, + "WsAlertTraderNewTradeSubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Subscribe to `trader_new_trade` alerts. Fired on every order-filled trade. Use `wallet_addresses` to watch specific traders, `min_usd_value` to filter by size, and `min_probability`/`max_probability` to restrict to a probability range.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "subscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "trader_new_trade" + ] + } + }, + "example": { + "op": "subscribe", + "event": "trader_new_trade", + "wallet_addresses": [ + "0x0000000000000000000000000000000000000000" + ], + "min_usd_value": 10000.0, + "min_probability": 0.95, + "max_probability": 0.05, + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "event_slugs": [ + "example-event" + ], + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/TraderNewTradeFilters" + } + ] + }, + "WsAlertTraderNewTradeUnsubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Unsubscribe from `trader_new_trade` alerts. The filter fields must match the original subscription exactly.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "unsubscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "trader_new_trade" + ] + } + }, + "example": { + "op": "unsubscribe", + "event": "trader_new_trade", + "wallet_addresses": [ + "0x0000000000000000000000000000000000000000" + ], + "min_usd_value": 10000.0, + "min_probability": 0.95, + "max_probability": 0.05, + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "event_slugs": [ + "example-event" + ], + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/TraderNewTradeFilters" + } + ] + }, + "WsAlertTraderNewTradeEvent": { + "type": "object", + "required": [ + "event", + "timestamp", + "data" + ], + "description": "Pushed `trader_new_trade` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "properties": { + "event": { + "type": "string", + "enum": [ + "trader_new_trade" + ] + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix timestamp in milliseconds" + }, + "data": { + "$ref": "#/components/schemas/NewTradePayload" + } + }, + "example": { + "event": "trader_new_trade", + "timestamp": 1743500000000, + "data": { + "trader": "0x0000000000000000000000000000000000000000", + "taker": "0x0000000000000000000000000000000000000000", + "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", + "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + "outcome": "Yes", + "outcome_index": 0, + "question": "Will this test webhook fire correctly?", + "market_slug": "test-market-0000000000", + "event_slug": "test-event-0000000000", + "trade_id": "00000000-0000-0000-0000-000000000000", + "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "block": 0, + "confirmed_at": 1700000000, + "amount_usd": 25.0, + "shares_amount": 50.0, + "fee": 0.025, + "side": "Buy", + "price": 0.5, + "probability": 0.5, + "exchange": "polymarket", + "trade_type": "OrderFilled" + } + } + }, + "WsAlertTraderGlobalPnlSubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Subscribe to `trader_global_pnl` alerts. Fired when a trader's global PnL crosses a configured threshold", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "subscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "trader_global_pnl" + ] + } + }, + "example": { + "op": "subscribe", + "event": "trader_global_pnl", + "traders": [ + "0x0000000000000000000000000000000000000000" + ], + "min_realized_pnl_usd": 1000.0, + "max_realized_pnl_usd": 5000.0, + "min_volume_usd": 10000.0, + "max_volume_usd": 100000.0, + "min_buy_usd": 5000.0, + "min_sell_volume_usd": 2500.0, + "min_win_rate": 60.0, + "min_markets_traded": 5, + "timeframes": [ + "1h" + ] + } + }, + { + "$ref": "#/components/schemas/TraderGlobalPnlFilters" + } + ] + }, + "WsAlertTraderGlobalPnlUnsubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Unsubscribe from `trader_global_pnl` alerts. The filter fields must match the original subscription exactly.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "unsubscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "trader_global_pnl" + ] + } + }, + "example": { + "op": "unsubscribe", + "event": "trader_global_pnl", + "traders": [ + "0x0000000000000000000000000000000000000000" + ], + "min_realized_pnl_usd": 1000.0, + "max_realized_pnl_usd": 5000.0, + "min_volume_usd": 10000.0, + "max_volume_usd": 100000.0, + "min_buy_usd": 5000.0, + "min_sell_volume_usd": 2500.0, + "min_win_rate": 60.0, + "min_markets_traded": 5, + "timeframes": [ + "1h" + ] + } + }, + { + "$ref": "#/components/schemas/TraderGlobalPnlFilters" + } + ] + }, + "WsAlertTraderGlobalPnlEvent": { + "type": "object", + "required": [ + "event", + "timestamp", + "data" + ], + "description": "Pushed `trader_global_pnl` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "properties": { + "event": { + "type": "string", + "enum": [ + "trader_global_pnl" + ] + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix timestamp in milliseconds" + }, + "data": { + "$ref": "#/components/schemas/GlobalPnlPayload" + } + }, + "example": { + "event": "trader_global_pnl", + "timestamp": 1743500000000, + "data": { + "trader": "0x0000000000000000000000000000000000000000", + "timeframe": "7d", + "realized_pnl_usd": 250.0, + "events_traded": 3, + "markets_traded": 5, + "total_buys": 12, + "total_sells": 8, + "total_redemptions": 1, + "total_merges": 0, + "total_volume_usd": 1500.0, + "buy_volume_usd": 900.0, + "sell_volume_usd": 600.0, + "redemption_volume_usd": 50.0, + "merge_volume_usd": 0.0, + "markets_won": 3, + "markets_lost": 2, + "market_win_rate_pct": 60.0, + "avg_pnl_per_market": 50.0, + "avg_pnl_per_trade": 12.5, + "avg_hold_time_seconds": 86400.0, + "total_fees": 7.5, + "best_trade_pnl_usd": 180.0, + "best_trade_condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + "first_trade_at": 1700000000, + "last_trade_at": 1700000000 + } + } + }, + "WsAlertTraderMarketPnlSubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Subscribe to `trader_market_pnl` alerts. Fired when a trader's market-level PnL crosses a configured threshold", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "subscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "trader_market_pnl" + ] + } + }, + "example": { + "op": "subscribe", + "event": "trader_market_pnl", + "traders": [ + "0x0000000000000000000000000000000000000000" + ], + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "event_slugs": [ + "example-event" + ], + "min_realized_pnl_usd": 1000.0, + "max_realized_pnl_usd": 5000.0, + "min_volume_usd": 10000.0, + "max_volume_usd": 100000.0, + "min_buy_usd": 5000.0, + "min_sell_volume_usd": 2500.0, + "timeframes": [ + "1h" + ], + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/TraderMarketPnlFilters" + } + ] + }, + "WsAlertTraderMarketPnlUnsubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Unsubscribe from `trader_market_pnl` alerts. The filter fields must match the original subscription exactly.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "unsubscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "trader_market_pnl" + ] + } + }, + "example": { + "op": "unsubscribe", + "event": "trader_market_pnl", + "traders": [ + "0x0000000000000000000000000000000000000000" + ], + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "event_slugs": [ + "example-event" + ], + "min_realized_pnl_usd": 1000.0, + "max_realized_pnl_usd": 5000.0, + "min_volume_usd": 10000.0, + "max_volume_usd": 100000.0, + "min_buy_usd": 5000.0, + "min_sell_volume_usd": 2500.0, + "timeframes": [ + "1h" + ], + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/TraderMarketPnlFilters" + } + ] + }, + "WsAlertTraderMarketPnlEvent": { + "type": "object", + "required": [ + "event", + "timestamp", + "data" + ], + "description": "Pushed `trader_market_pnl` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "properties": { + "event": { + "type": "string", + "enum": [ + "trader_market_pnl" + ] + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix timestamp in milliseconds" + }, + "data": { + "$ref": "#/components/schemas/MarketPnlPayload" + } + }, + "example": { + "event": "trader_market_pnl", + "timestamp": 1743500000000, + "data": { + "trader": "0x0000000000000000000000000000000000000000", + "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + "event_slug": "test-event-0000000000", + "timeframe": "7d", + "outcomes_traded": 2, + "total_buys": 4, + "total_sells": 3, + "total_redemptions": 1, + "total_merges": 0, + "buy_usd": 300.0, + "sell_usd": 200.0, + "redemption_usd": 50.0, + "merge_usd": 0.0, + "realized_pnl_usd": 100.0, + "winning_outcomes": 1, + "total_fees": 2.5, + "first_trade_at": 1700000000, + "last_trade_at": 1700000000 + } + } + }, + "WsAlertTraderEventPnlSubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Subscribe to `trader_event_pnl` alerts. Fired when a trader's event-level PnL crosses a configured threshold", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "subscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "trader_event_pnl" + ] + } + }, + "example": { + "op": "subscribe", + "event": "trader_event_pnl", + "traders": [ + "0x0000000000000000000000000000000000000000" + ], + "event_slugs": [ + "example-event" + ], + "min_realized_pnl_usd": 1000.0, + "max_realized_pnl_usd": 5000.0, + "min_volume_usd": 10000.0, + "max_volume_usd": 100000.0, + "min_buy_usd": 5000.0, + "min_sell_volume_usd": 2500.0, + "min_markets_traded": 5, + "timeframes": [ + "1h" + ], + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/TraderEventPnlFilters" + } + ] + }, + "WsAlertTraderEventPnlUnsubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Unsubscribe from `trader_event_pnl` alerts. The filter fields must match the original subscription exactly.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "unsubscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "trader_event_pnl" + ] + } + }, + "example": { + "op": "unsubscribe", + "event": "trader_event_pnl", + "traders": [ + "0x0000000000000000000000000000000000000000" + ], + "event_slugs": [ + "example-event" + ], + "min_realized_pnl_usd": 1000.0, + "max_realized_pnl_usd": 5000.0, + "min_volume_usd": 10000.0, + "max_volume_usd": 100000.0, + "min_buy_usd": 5000.0, + "min_sell_volume_usd": 2500.0, + "min_markets_traded": 5, + "timeframes": [ + "1h" + ], + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/TraderEventPnlFilters" + } + ] + }, + "WsAlertTraderEventPnlEvent": { + "type": "object", + "required": [ + "event", + "timestamp", + "data" + ], + "description": "Pushed `trader_event_pnl` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "properties": { + "event": { + "type": "string", + "enum": [ + "trader_event_pnl" + ] + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix timestamp in milliseconds" + }, + "data": { + "$ref": "#/components/schemas/EventPnlPayload" + } + }, + "example": { + "event": "trader_event_pnl", + "timestamp": 1743500000000, + "data": { + "trader": "0x0000000000000000000000000000000000000000", + "event_slug": "test-event-0000000000", + "timeframe": "7d", + "markets_traded": 2, + "outcomes_traded": 3, + "total_buys": 6, + "total_sells": 4, + "total_redemptions": 1, + "total_merges": 0, + "total_volume_usd": 800.0, + "buy_usd": 480.0, + "sell_usd": 320.0, + "redemption_usd": 50.0, + "merge_usd": 0.0, + "realized_pnl_usd": 150.0, + "winning_markets": 1, + "losing_markets": 1, + "total_fees": 4.0, + "first_trade_at": 1700000000, + "last_trade_at": 1700000000 + } + } + }, + "WsAlertConditionMetricsSubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Subscribe to `condition_metrics` alerts. Fired when a market's volume or transaction metrics cross a configured threshold. Use `timeframes` to restrict to specific windows (valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`).", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "subscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "condition_metrics" + ] + } + }, + "example": { + "op": "subscribe", + "event": "condition_metrics", + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "min_volume_usd": 10000.0, + "max_volume_usd": 100000.0, + "min_fees": 100.0, + "min_txns": 10, + "min_unique_traders": 10, + "timeframes": [ + "1h" + ] + } + }, + { + "$ref": "#/components/schemas/MarketMetricsFilters" + } + ] + }, + "WsAlertConditionMetricsUnsubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Unsubscribe from `condition_metrics` alerts. The filter fields must match the original subscription exactly.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "unsubscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "condition_metrics" + ] + } + }, + "example": { + "op": "unsubscribe", + "event": "condition_metrics", + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "min_volume_usd": 10000.0, + "max_volume_usd": 100000.0, + "min_fees": 100.0, + "min_txns": 10, + "min_unique_traders": 10, + "timeframes": [ + "1h" + ] + } + }, + { + "$ref": "#/components/schemas/MarketMetricsFilters" + } + ] + }, + "WsAlertConditionMetricsEvent": { + "type": "object", + "required": [ + "event", + "timestamp", + "data" + ], + "description": "Pushed `condition_metrics` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "properties": { + "event": { + "type": "string", + "enum": [ + "condition_metrics" + ] + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix timestamp in milliseconds" + }, + "data": { + "$ref": "#/components/schemas/ConditionMetricsPayload" + } + }, + "example": { + "event": "condition_metrics", + "timestamp": 1743500000000, + "data": { + "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + "timeframe": "1h", + "volume_usd": 50000.0, + "fees": 250.0, + "txns": 320, + "unique_traders": 85 + } + } + }, + "WsAlertEventMetricsSubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Subscribe to `event_metrics` alerts. Fired when an event's volume or transaction metrics cross a configured threshold. Use `timeframes` to restrict to specific windows (valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`).", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "subscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "event_metrics" + ] + } + }, + "example": { + "op": "subscribe", + "event": "event_metrics", + "event_slugs": [ + "example-event" + ], + "min_volume_usd": 10000.0, + "max_volume_usd": 100000.0, + "min_fees": 100.0, + "min_txns": 10, + "min_unique_traders": 10, + "timeframes": [ + "1h" + ], + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/EventMetricsFilters" + } + ] + }, + "WsAlertEventMetricsUnsubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Unsubscribe from `event_metrics` alerts. The filter fields must match the original subscription exactly.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "unsubscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "event_metrics" + ] + } + }, + "example": { + "op": "unsubscribe", + "event": "event_metrics", + "event_slugs": [ + "example-event" + ], + "min_volume_usd": 10000.0, + "max_volume_usd": 100000.0, + "min_fees": 100.0, + "min_txns": 10, + "min_unique_traders": 10, + "timeframes": [ + "1h" + ], + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/EventMetricsFilters" + } + ] + }, + "WsAlertEventMetricsEvent": { + "type": "object", + "required": [ + "event", + "timestamp", + "data" + ], + "description": "Pushed `event_metrics` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "properties": { + "event": { + "type": "string", + "enum": [ + "event_metrics" + ] + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix timestamp in milliseconds" + }, + "data": { + "$ref": "#/components/schemas/EventMetricsPayload" + } + }, + "example": { + "event": "event_metrics", + "timestamp": 1743500000000, + "data": { + "event_slug": "test-event-0000000000", + "timeframe": "1h", + "volume_usd": 120000.0, + "fees": 600.0, + "txns": 740, + "unique_traders": 210 + } + } + }, + "WsAlertPositionMetricsSubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Subscribe to `position_metrics` alerts. Fired when a position's volume or transaction metrics cross a configured threshold. Use `timeframes` to restrict to specific windows (valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`).", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "subscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "position_metrics" + ] + } + }, + "example": { + "op": "subscribe", + "event": "position_metrics", + "position_ids": [ + "452312848583266388373324160190187140051835877600158453279131187530910662656" + ], + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "outcomes": [ + "Yes" + ], + "min_volume_usd": 10000.0, + "max_volume_usd": 100000.0, + "min_buy_usd": 5000.0, + "min_sell_volume_usd": 2500.0, + "min_fees": 100.0, + "min_txns": 10, + "min_price_change_pct": 10.0, + "min_probability_change_pct": 10.0, + "timeframes": [ + "1h" + ] + } + }, + { + "$ref": "#/components/schemas/PositionMetricsFilters" + } + ] + }, + "WsAlertPositionMetricsUnsubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Unsubscribe from `position_metrics` alerts. The filter fields must match the original subscription exactly.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "unsubscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "position_metrics" + ] + } + }, + "example": { + "op": "unsubscribe", + "event": "position_metrics", + "position_ids": [ + "452312848583266388373324160190187140051835877600158453279131187530910662656" + ], + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "outcomes": [ + "Yes" + ], + "min_volume_usd": 10000.0, + "max_volume_usd": 100000.0, + "min_buy_usd": 5000.0, + "min_sell_volume_usd": 2500.0, + "min_fees": 100.0, + "min_txns": 10, + "min_price_change_pct": 10.0, + "min_probability_change_pct": 10.0, + "timeframes": [ + "1h" + ] + } + }, + { + "$ref": "#/components/schemas/PositionMetricsFilters" + } + ] + }, + "WsAlertPositionMetricsEvent": { + "type": "object", + "required": [ + "event", + "timestamp", + "data" + ], + "description": "Pushed `position_metrics` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "properties": { + "event": { + "type": "string", + "enum": [ + "position_metrics" + ] + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix timestamp in milliseconds" + }, + "data": { + "$ref": "#/components/schemas/PositionMetricsPayload" + } + }, + "example": { + "event": "position_metrics", + "timestamp": 1743500000000, + "data": { + "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", + "outcome": "Yes", + "outcome_index": 0, + "timeframe": "1h", + "volume_usd": 25000.0, + "buy_volume_usd": 15000.0, + "sell_volume_usd": 10000.0, + "fees": 125.0, + "txns": 160, + "buys": 95, + "sells": 65, + "unique_traders": 48, + "price_open": 0.48, + "price_close": 0.52, + "price_high": 0.55, + "price_low": 0.46, + "probability_open": 0.48, + "probability_close": 0.52, + "probability_high": 0.55, + "probability_low": 0.46 + } + } + }, + "WsAlertMarketVolumeMilestoneSubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Subscribe to `market_volume_milestone` alerts. Fired when a market's trading volume crosses a milestone threshold in the specified timeframe. **`timeframes` is required** (e.g. `[\"1h\", \"24h\"]`) — valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`. Optional `milestone_amounts` restricts to specific USD thresholds (e.g. `[10000, 100000]`). Optional `condition_ids` restricts to specific markets.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "subscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "market_volume_milestone" + ] + } + }, + "example": { + "op": "subscribe", + "event": "market_volume_milestone", + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "timeframes": [ + "1h" + ], + "milestone_amounts": [ + 10000 + ] + } + }, + { + "$ref": "#/components/schemas/MarketVolumeMilestoneFilters" + } + ] + }, + "WsAlertMarketVolumeMilestoneUnsubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Unsubscribe from `market_volume_milestone` alerts. The filter fields must match the original subscription exactly.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "unsubscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "market_volume_milestone" + ] + } + }, + "example": { + "op": "unsubscribe", + "event": "market_volume_milestone", + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "timeframes": [ + "1h" + ], + "milestone_amounts": [ + 10000 + ] + } + }, + { + "$ref": "#/components/schemas/MarketVolumeMilestoneFilters" + } + ] + }, + "WsAlertMarketVolumeMilestoneEvent": { + "type": "object", + "required": [ + "event", + "timestamp", + "data" + ], + "description": "Pushed `market_volume_milestone` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "properties": { + "event": { + "type": "string", + "enum": [ + "market_volume_milestone" + ] + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix timestamp in milliseconds" + }, + "data": { + "$ref": "#/components/schemas/VolumeMilestonePayload" + } + }, + "example": { + "event": "market_volume_milestone", + "timestamp": 1743500000000, + "data": { + "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + "timeframe": "24h", + "milestone_usd": 100000.0, + "current_volume_usd": 100125.0, + "fees": 500.0, + "txns": 650 + } + } + }, + "WsAlertEventVolumeMilestoneSubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Subscribe to `event_volume_milestone` alerts. Fired when an event's trading volume crosses a milestone threshold in the specified timeframe. **`timeframes` is required** (e.g. `[\"1h\", \"24h\"]`) — valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`. Optional `milestone_amounts` restricts to specific USD thresholds. Optional `event_slugs` restricts to specific events.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "subscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "event_volume_milestone" + ] + } + }, + "example": { + "op": "subscribe", + "event": "event_volume_milestone", + "event_slugs": [ + "example-event" + ], + "timeframes": [ + "1h" + ], + "milestone_amounts": [ + 10000 + ], + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/EventVolumeMilestoneFilters" + } + ] + }, + "WsAlertEventVolumeMilestoneUnsubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Unsubscribe from `event_volume_milestone` alerts. The filter fields must match the original subscription exactly.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "unsubscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "event_volume_milestone" + ] + } + }, + "example": { + "op": "unsubscribe", + "event": "event_volume_milestone", + "event_slugs": [ + "example-event" + ], + "timeframes": [ + "1h" + ], + "milestone_amounts": [ + 10000 + ], + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/EventVolumeMilestoneFilters" + } + ] + }, + "WsAlertEventVolumeMilestoneEvent": { + "type": "object", + "required": [ + "event", + "timestamp", + "data" + ], + "description": "Pushed `event_volume_milestone` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "properties": { + "event": { + "type": "string", + "enum": [ + "event_volume_milestone" + ] + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix timestamp in milliseconds" + }, + "data": { + "$ref": "#/components/schemas/EventVolumeMilestonePayload" + } + }, + "example": { + "event": "event_volume_milestone", + "timestamp": 1743500000000, + "data": { + "event_slug": "test-event-0000000000", + "timeframe": "24h", + "milestone_usd": 500000.0, + "current_volume_usd": 500250.0, + "fees": 2500.0, + "txns": 3200 + } + } + }, + "WsAlertPositionVolumeMilestoneSubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Subscribe to `position_volume_milestone` alerts. Fired when a position's trading volume crosses a milestone threshold in the specified timeframe. **`timeframes` is required** (e.g. `[\"1h\", \"24h\"]`) — valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`. Optional `milestone_amounts` restricts to specific USD thresholds. Optional `position_ids` or `condition_ids` restrict to specific positions/markets.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "subscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "position_volume_milestone" + ] + } + }, + "example": { + "op": "subscribe", + "event": "position_volume_milestone", + "position_ids": [ + "452312848583266388373324160190187140051835877600158453279131187530910662656" + ], + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "outcomes": [ + "Yes" + ], + "timeframes": [ + "1h" + ], + "milestone_amounts": [ + 10000 + ] + } + }, + { + "$ref": "#/components/schemas/PositionVolumeMilestoneFilters" + } + ] + }, + "WsAlertPositionVolumeMilestoneUnsubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Unsubscribe from `position_volume_milestone` alerts. The filter fields must match the original subscription exactly.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "unsubscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "position_volume_milestone" + ] + } + }, + "example": { + "op": "unsubscribe", + "event": "position_volume_milestone", + "position_ids": [ + "452312848583266388373324160190187140051835877600158453279131187530910662656" + ], + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "outcomes": [ + "Yes" + ], + "timeframes": [ + "1h" + ], + "milestone_amounts": [ + 10000 + ] + } + }, + { + "$ref": "#/components/schemas/PositionVolumeMilestoneFilters" + } + ] + }, + "WsAlertPositionVolumeMilestoneEvent": { + "type": "object", + "required": [ + "event", + "timestamp", + "data" + ], + "description": "Pushed `position_volume_milestone` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "properties": { + "event": { + "type": "string", + "enum": [ + "position_volume_milestone" + ] + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix timestamp in milliseconds" + }, + "data": { + "$ref": "#/components/schemas/PositionVolumeMilestonePayload" + } + }, + "example": { + "event": "position_volume_milestone", + "timestamp": 1743500000000, + "data": { + "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", + "outcome": "Yes", + "outcome_index": 0, + "timeframe": "24h", + "milestone_usd": 50000.0, + "current_volume_usd": 50125.0, + "buy_volume_usd": 30000.0, + "sell_volume_usd": 20000.0, + "fees": 250.0, + "txns": 320, + "buys": 190, + "sells": 130 + } + } + }, + "WsAlertProbabilitySpikeSubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Subscribe to `probability_spike` alerts. Fired when a position's probability moves significantly. Use `min_probability_change_pct` to set the minimum move (e.g. `10` for 10%). Use `window_secs` to observe moves within a specific time window (e.g. `60` for 60 seconds). Use `spike_direction` (`\"up\"` | `\"down\"` | `\"both\"`) — defaults to `\"up\"` when not provided. Filter by `position_ids` or `outcomes` to narrow scope.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "subscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "probability_spike" + ] + } + }, + "example": { + "op": "subscribe", + "event": "probability_spike", + "position_ids": [ + "452312848583266388373324160190187140051835877600158453279131187530910662656" + ], + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "event_slugs": [ + "example-event" + ], + "outcomes": [ + "Yes" + ], + "min_probability_change_pct": 10.0, + "spike_direction": "up", + "window_secs": 60, + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/ProbabilitySpikeFilters" + } + ] + }, + "WsAlertProbabilitySpikeUnsubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Unsubscribe from `probability_spike` alerts. The filter fields must match the original subscription exactly.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "unsubscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "probability_spike" + ] + } + }, + "example": { + "op": "unsubscribe", + "event": "probability_spike", + "position_ids": [ + "452312848583266388373324160190187140051835877600158453279131187530910662656" + ], + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "event_slugs": [ + "example-event" + ], + "outcomes": [ + "Yes" + ], + "min_probability_change_pct": 10.0, + "spike_direction": "up", + "window_secs": 60, + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/ProbabilitySpikeFilters" + } + ] + }, + "WsAlertProbabilitySpikeEvent": { + "type": "object", + "required": [ + "event", + "timestamp", + "data" + ], + "description": "Pushed `probability_spike` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "properties": { + "event": { + "type": "string", + "enum": [ + "probability_spike" + ] + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix timestamp in milliseconds" + }, + "data": { + "$ref": "#/components/schemas/ProbabilitySpikePayload" + } + }, + "example": { + "event": "probability_spike", + "timestamp": 1743500000000, + "data": { + "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", + "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + "event_slug": "test-event-0000000000", + "outcome": "Yes", + "outcome_index": 0, + "previous_probability": 0.4, + "current_probability": 0.5, + "spike_direction": "up", + "spike_pct": 25.0 + } + } + }, + "WsAlertPriceSpikeSubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Subscribe to `price_spike` alerts. Fired when a position's price moves significantly. Use `min_price_change_pct` to set the minimum move (e.g. `10` for 10%). Use `window_secs` to observe moves within a specific time window. Use `spike_direction` (`\"up\"` | `\"down\"` | `\"both\"`) — defaults to `\"up\"` when not provided. Filter by `position_ids` or `outcomes` to narrow scope.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "subscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "price_spike" + ] + } + }, + "example": { + "op": "subscribe", + "event": "price_spike", + "position_ids": [ + "452312848583266388373324160190187140051835877600158453279131187530910662656" + ], + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "event_slugs": [ + "example-event" + ], + "outcomes": [ + "Yes" + ], + "min_price_change_pct": 10.0, + "spike_direction": "up", + "window_secs": 60, + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/PriceSpikeFilters" + } + ] + }, + "WsAlertPriceSpikeUnsubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Unsubscribe from `price_spike` alerts. The filter fields must match the original subscription exactly.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "unsubscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "price_spike" + ] + } + }, + "example": { + "op": "unsubscribe", + "event": "price_spike", + "position_ids": [ + "452312848583266388373324160190187140051835877600158453279131187530910662656" + ], + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "event_slugs": [ + "example-event" + ], + "outcomes": [ + "Yes" + ], + "min_price_change_pct": 10.0, + "spike_direction": "up", + "window_secs": 60, + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/PriceSpikeFilters" + } + ] + }, + "WsAlertPriceSpikeEvent": { + "type": "object", + "required": [ + "event", + "timestamp", + "data" + ], + "description": "Pushed `price_spike` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "properties": { + "event": { + "type": "string", + "enum": [ + "price_spike" + ] + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix timestamp in milliseconds" + }, + "data": { + "$ref": "#/components/schemas/PriceSpikePayload" + } + }, + "example": { + "event": "price_spike", + "timestamp": 1743500000000, + "data": { + "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", + "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + "event_slug": "test-event-0000000000", + "outcome": "Yes", + "outcome_index": 0, + "previous_price": 0.4, + "current_price": 0.5, + "spike_direction": "up", + "spike_pct": 25.0 + } + } + }, + "WsAlertMarketVolumeSpikeSubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Subscribe to `market_volume_spike` alerts. Fired when a market's trading volume grows by a multiple of `spike_ratio` within a timeframe. Requires `spike_ratio` (> 1.0, e.g. `2.0` fires when volume doubles). Optional `window_secs` sets the observation window in seconds (max 600). Optional `timeframes` — valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `1d`, `24h`, `7d`, `30d`. Optional `condition_ids` restricts to specific markets.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "subscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "market_volume_spike" + ] + } + }, + "example": { + "op": "subscribe", + "event": "market_volume_spike", + "spike_ratio": 2.0, + "window_secs": 60, + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "timeframes": [ + "1h" + ] + } + }, + { + "$ref": "#/components/schemas/MarketVolumeSpikeFilters" + } + ] + }, + "WsAlertMarketVolumeSpikeUnsubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Unsubscribe from `market_volume_spike` alerts. The filter fields must match the original subscription exactly.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "unsubscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "market_volume_spike" + ] + } + }, + "example": { + "op": "unsubscribe", + "event": "market_volume_spike", + "spike_ratio": 2.0, + "window_secs": 60, + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "timeframes": [ + "1h" + ] + } + }, + { + "$ref": "#/components/schemas/MarketVolumeSpikeFilters" + } + ] + }, + "WsAlertMarketVolumeSpikeEvent": { + "type": "object", + "required": [ + "event", + "timestamp", + "data" + ], + "description": "Pushed `market_volume_spike` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "properties": { + "event": { + "type": "string", + "enum": [ + "market_volume_spike" + ] + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix timestamp in milliseconds" + }, + "data": { + "$ref": "#/components/schemas/MarketVolumeSpikePayload" + } + }, + "example": { + "event": "market_volume_spike", + "timestamp": 1743500000000, + "data": { + "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + "timeframe": "1h", + "current_volume_usd": 32000.0, + "snapshot_volume_usd": 10000.0, + "delta_volume_usd": 22000.0, + "spike_pct": 220.0, + "txns": 480, + "fees": 160.0 + } + } + }, + "WsAlertEventVolumeSpikeSubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Subscribe to `event_volume_spike` alerts. Fired when an event's aggregated trading volume grows by a multiple of `spike_ratio` within a timeframe. Requires `spike_ratio` (> 1.0, e.g. `2.0` fires when volume doubles). Optional `window_secs` sets the observation window in seconds (max 600). Optional `timeframes` and `event_slugs` to narrow scope.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "subscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "event_volume_spike" + ] + } + }, + "example": { + "op": "subscribe", + "event": "event_volume_spike", + "spike_ratio": 2.0, + "window_secs": 60, + "event_slugs": [ + "example-event" + ], + "timeframes": [ + "1h" + ], + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/EventVolumeSpikeFilters" + } + ] + }, + "WsAlertEventVolumeSpikeUnsubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Unsubscribe from `event_volume_spike` alerts. The filter fields must match the original subscription exactly.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "unsubscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "event_volume_spike" + ] + } + }, + "example": { + "op": "unsubscribe", + "event": "event_volume_spike", + "spike_ratio": 2.0, + "window_secs": 60, + "event_slugs": [ + "example-event" + ], + "timeframes": [ + "1h" + ], + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/EventVolumeSpikeFilters" + } + ] + }, + "WsAlertEventVolumeSpikeEvent": { + "type": "object", + "required": [ + "event", + "timestamp", + "data" + ], + "description": "Pushed `event_volume_spike` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "properties": { + "event": { + "type": "string", + "enum": [ + "event_volume_spike" + ] + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix timestamp in milliseconds" + }, + "data": { + "$ref": "#/components/schemas/EventVolumeSpikePayload" + } + }, + "example": { + "event": "event_volume_spike", + "timestamp": 1743500000000, + "data": { + "event_slug": "test-event-0000000000", + "timeframe": "1h", + "current_volume_usd": 140000.0, + "snapshot_volume_usd": 50000.0, + "delta_volume_usd": 90000.0, + "spike_pct": 180.0, + "txns": 1100, + "fees": 700.0 + } + } + }, + "WsAlertPositionVolumeSpikeSubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Subscribe to `position_volume_spike` alerts. Fired when a position's trading volume grows by a multiple of `spike_ratio` within a timeframe. Requires `spike_ratio` (> 1.0, e.g. `2.0` fires when volume doubles). Optional `window_secs` sets the observation window in seconds (max 600). Optional `position_ids`, `condition_ids`, `outcomes`, and `timeframes` to narrow scope.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "subscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "position_volume_spike" + ] + } + }, + "example": { + "op": "subscribe", + "event": "position_volume_spike", + "spike_ratio": 2.0, + "window_secs": 60, + "position_ids": [ + "452312848583266388373324160190187140051835877600158453279131187530910662656" + ], + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "outcomes": [ + "Yes" + ], + "timeframes": [ + "1h" + ] + } + }, + { + "$ref": "#/components/schemas/PositionVolumeSpikeFilters" + } + ] + }, + "WsAlertPositionVolumeSpikeUnsubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Unsubscribe from `position_volume_spike` alerts. The filter fields must match the original subscription exactly.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "unsubscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "position_volume_spike" + ] + } + }, + "example": { + "op": "unsubscribe", + "event": "position_volume_spike", + "spike_ratio": 2.0, + "window_secs": 60, + "position_ids": [ + "452312848583266388373324160190187140051835877600158453279131187530910662656" + ], + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "outcomes": [ + "Yes" + ], + "timeframes": [ + "1h" + ] + } + }, + { + "$ref": "#/components/schemas/PositionVolumeSpikeFilters" + } + ] + }, + "WsAlertPositionVolumeSpikeEvent": { + "type": "object", + "required": [ + "event", + "timestamp", + "data" + ], + "description": "Pushed `position_volume_spike` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "properties": { + "event": { + "type": "string", + "enum": [ + "position_volume_spike" + ] + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix timestamp in milliseconds" + }, + "data": { + "$ref": "#/components/schemas/PositionVolumeSpikePayload" + } + }, + "example": { + "event": "position_volume_spike", + "timestamp": 1743500000000, + "data": { + "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", + "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + "outcome": "Yes", + "outcome_index": 0, + "timeframe": "1h", + "current_volume_usd": 20500.0, + "snapshot_volume_usd": 5000.0, + "delta_volume_usd": 15500.0, + "spike_pct": 310.0, + "txns": 240, + "fees": 102.5 + } + } + }, + "WsAlertCloseToBondSubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Subscribe to `close_to_bond` alerts. Fired when a trade occurs at a near-certain-outcome price. **At least one of `min_probability` or `max_probability` is required.** Use `min_probability` (e.g. `0.95`) to trigger when YES is near-certain; use `max_probability` (e.g. `0.05`) for NO near-certain. Optional filters: `position_outcome_indices` — restrict by outcome index (`0` = Yes/Up, `1` = No); `condition_ids` — restrict to specific markets; `position_ids` — restrict to specific outcome tokens; `outcomes` — restrict by outcome name (e.g. `\"Yes\"`, `\"No\"`); `event_slugs` — restrict to specific events.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "subscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "close_to_bond" + ] + } + }, + "example": { + "op": "subscribe", + "event": "close_to_bond", + "min_probability": 0.95, + "max_probability": 0.05, + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "position_ids": [ + "452312848583266388373324160190187140051835877600158453279131187530910662656" + ], + "outcomes": [ + "Yes" + ], + "position_outcome_indices": [ + 0 + ], + "event_slugs": [ + "example-event" + ], + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/CloseToBondFilters" + } + ], + "anyOf": [ + { + "required": [ + "min_probability" + ] + }, + { + "required": [ + "max_probability" + ] + } + ] + }, + "WsAlertCloseToBondUnsubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Unsubscribe from `close_to_bond` alerts. The filter fields must match the original subscription exactly.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "unsubscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "close_to_bond" + ] + } + }, + "example": { + "op": "unsubscribe", + "event": "close_to_bond", + "min_probability": 0.95, + "max_probability": 0.05, + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "position_ids": [ + "452312848583266388373324160190187140051835877600158453279131187530910662656" + ], + "outcomes": [ + "Yes" + ], + "position_outcome_indices": [ + 0 + ], + "event_slugs": [ + "example-event" + ], + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/CloseToBondFilters" + } + ], + "anyOf": [ + { + "required": [ + "min_probability" + ] + }, + { + "required": [ + "max_probability" + ] + } + ] + }, + "WsAlertCloseToBondEvent": { + "type": "object", + "required": [ + "event", + "timestamp", + "data" + ], + "description": "Pushed `close_to_bond` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "properties": { + "event": { + "type": "string", + "enum": [ + "close_to_bond" + ] + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix timestamp in milliseconds" + }, + "data": { + "$ref": "#/components/schemas/CloseToBondPayload" + } + }, + "example": { + "event": "close_to_bond", + "timestamp": 1743500000000, + "data": { + "trader": "0x0000000000000000000000000000000000000000", + "taker": "0x0000000000000000000000000000000000000000", + "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", + "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + "outcome": "Yes", + "outcome_index": 0, + "question": "Will this test webhook fire correctly?", + "market_slug": "test-market-0000000000", + "event_slug": "test-event-0000000000", + "trade_id": "00000000-0000-0000-0000-000000000000", + "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "block": 0, + "confirmed_at": 1700000000, + "amount_usd": 500.0, + "shares_amount": 515.46, + "fee": 2.5, + "side": "Buy", + "price": 0.97, + "probability": 0.97, + "bond_side": "high", + "threshold": 0.95 + } + } + }, + "WsAlertMarketCreatedSubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Subscribe to `market_created` alerts. Fired when a new prediction market is created on Polymarket. Filterable by `tags` and `event_slugs`.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "subscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "market_created" + ] + } + }, + "example": { + "op": "subscribe", + "event": "market_created", + "event_slugs": [ + "example-event" + ], + "tags": [ + "Politics" + ], + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/MarketCreatedFilters" + } + ] + }, + "WsAlertMarketCreatedUnsubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Unsubscribe from `market_created` alerts. The filter fields must match the original subscription exactly.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "unsubscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "market_created" + ] + } + }, + "example": { + "op": "unsubscribe", + "event": "market_created", + "event_slugs": [ + "example-event" + ], + "tags": [ + "Politics" + ], + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/MarketCreatedFilters" + } + ] + }, + "WsAlertMarketCreatedEvent": { + "type": "object", + "required": [ + "event", + "timestamp", + "data" + ], + "description": "Pushed `market_created` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "properties": { + "event": { + "type": "string", + "enum": [ + "market_created" + ] + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix timestamp in milliseconds" + }, + "data": { + "$ref": "#/components/schemas/MarketCreatedPayload" + } + }, + "example": { + "event": "market_created", + "timestamp": 1743500000000, + "data": { + "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + "market_slug": "test-market-0000000000", + "event_slug": "test-event-0000000000", + "event_id": null, + "event_title": "Test Event 0000", + "series_slug": null, + "outcomes": [ + { + "index": 0, + "name": "Yes", + "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656" + }, + { + "index": 1, + "name": "No", + "position_id": "0" + } + ], + "question": "Will this test webhook fire correctly?", + "title": "Test Market 0000", + "description": "A test market for webhook payload verification.", + "category": "Crypto", + "tags": [ + "test", + "crypto" + ], + "image_url": null, + "neg_risk": false + } + } + }, + "WsAlertAssetPriceTickSubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Subscribe to `asset_price_tick` alerts. Fired when the price of a tracked crypto asset updates (BTC, ETH, SOL, XRP, DOGE, BNB, HYPE). Use `asset_symbols` to restrict to specific assets (empty = all).", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "subscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "asset_price_tick" + ] + } + }, + "example": { + "op": "subscribe", + "event": "asset_price_tick", + "asset_symbols": [ + "BTC" + ] + } + }, + { + "$ref": "#/components/schemas/AssetPriceTickFilters" + } + ] + }, + "WsAlertAssetPriceTickUnsubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Unsubscribe from `asset_price_tick` alerts. The filter fields must match the original subscription exactly.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "unsubscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "asset_price_tick" + ] + } + }, + "example": { + "op": "unsubscribe", + "event": "asset_price_tick", + "asset_symbols": [ + "BTC" + ] + } + }, + { + "$ref": "#/components/schemas/AssetPriceTickFilters" + } + ] + }, + "WsAlertAssetPriceTickEvent": { + "type": "object", + "required": [ + "event", + "timestamp", + "data" + ], + "description": "Pushed `asset_price_tick` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "properties": { + "event": { + "type": "string", + "enum": [ + "asset_price_tick" + ] + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix timestamp in milliseconds" + }, + "data": { + "$ref": "#/components/schemas/AssetPriceTickPayload" + } + }, + "example": { + "event": "asset_price_tick", + "timestamp": 1743500000000, + "data": { + "symbol": "BTC", + "price": 65000.0, + "timestamp_ms": 1700000000000 + } + } + }, + "WsAlertAssetPriceWindowUpdateSubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Subscribe to `asset_price_window_update` alerts. Fired at the start and end of each price candle for tracked crypto assets (BTC, ETH, SOL, XRP, DOGE, BNB, HYPE). Payload includes `update_type` (`\"open\"` or `\"close\"`) indicating whether the candle is opening or closing. Use `asset_symbols` to restrict to specific assets. Use `timeframes` to restrict to specific candle sizes — valid values: `\"5m\"`, `\"15m\"`, `\"1h\"`, `\"4h\"`, `\"1d\"`, `\"24h\"`.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "subscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "asset_price_window_update" + ] + } + }, + "example": { + "op": "subscribe", + "event": "asset_price_window_update", + "asset_symbols": [ + "BTC" + ], + "timeframes": [ + "1h" + ] + } + }, + { + "$ref": "#/components/schemas/AssetPriceWindowUpdateFilters" + } + ] + }, + "WsAlertAssetPriceWindowUpdateUnsubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Unsubscribe from `asset_price_window_update` alerts. The filter fields must match the original subscription exactly.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "unsubscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "asset_price_window_update" + ] + } + }, + "example": { + "op": "unsubscribe", + "event": "asset_price_window_update", + "asset_symbols": [ + "BTC" + ], + "timeframes": [ + "1h" + ] + } + }, + { + "$ref": "#/components/schemas/AssetPriceWindowUpdateFilters" + } + ] + }, + "WsAlertAssetPriceWindowUpdateEvent": { + "type": "object", + "required": [ + "event", + "timestamp", + "data" + ], + "description": "Pushed `asset_price_window_update` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "properties": { + "event": { + "type": "string", + "enum": [ + "asset_price_window_update" + ] + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix timestamp in milliseconds" + }, + "data": { + "$ref": "#/components/schemas/AssetPriceWindowUpdatePayload" + } + }, + "example": { + "event": "asset_price_window_update", + "timestamp": 1743500000000, + "data": { + "symbol": "BTC", + "variant": "1h", + "start_time": 1700000000000, + "end_time": 1700003600000, + "open_price": 64800.0, + "close_price": 65200.0, + "update_type": "close" + } + } + }, + "WsAlertSubscribeMessage": { + "description": "Typed subscribe request for the alerts WebSocket. The request shape depends on `event` and reuses the matching webhook filter schema.", + "oneOf": [ + { + "$ref": "#/components/schemas/WsAlertTraderFirstTradeSubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertTraderNewMarketSubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertTraderWhaleTradeSubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertTraderNewTradeSubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertTraderGlobalPnlSubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertTraderMarketPnlSubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertTraderEventPnlSubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertConditionMetricsSubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertEventMetricsSubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertPositionMetricsSubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertMarketVolumeMilestoneSubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertEventVolumeMilestoneSubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertPositionVolumeMilestoneSubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertProbabilitySpikeSubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertPriceSpikeSubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertMarketVolumeSpikeSubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertEventVolumeSpikeSubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertPositionVolumeSpikeSubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertCloseToBondSubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertMarketCreatedSubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertAssetPriceTickSubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertAssetPriceWindowUpdateSubscribeMessage" + } + ], + "discriminator": { + "propertyName": "event" + } + }, + "WsAlertUnsubscribeMessage": { + "description": "Typed unsubscribe request for the alerts WebSocket. The request shape depends on `event` and must match the original subscription filters.", + "oneOf": [ + { + "$ref": "#/components/schemas/WsAlertTraderFirstTradeUnsubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertTraderNewMarketUnsubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertTraderWhaleTradeUnsubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertTraderNewTradeUnsubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertTraderGlobalPnlUnsubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertTraderMarketPnlUnsubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertTraderEventPnlUnsubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertConditionMetricsUnsubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertEventMetricsUnsubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertPositionMetricsUnsubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertMarketVolumeMilestoneUnsubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertEventVolumeMilestoneUnsubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertPositionVolumeMilestoneUnsubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertProbabilitySpikeUnsubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertPriceSpikeUnsubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertMarketVolumeSpikeUnsubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertEventVolumeSpikeUnsubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertPositionVolumeSpikeUnsubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertCloseToBondUnsubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertMarketCreatedUnsubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertAssetPriceTickUnsubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertAssetPriceWindowUpdateUnsubscribeMessage" + } + ], + "discriminator": { + "propertyName": "event" + } + }, + "WsAlertEventPayload": { + "description": "Typed pushed-event envelope for the alerts WebSocket. The `data` payload depends on `event` and matches the corresponding HTTP webhook payload schema.", + "oneOf": [ + { + "$ref": "#/components/schemas/WsAlertTraderFirstTradeEvent" + }, + { + "$ref": "#/components/schemas/WsAlertTraderNewMarketEvent" + }, + { + "$ref": "#/components/schemas/WsAlertTraderWhaleTradeEvent" + }, + { + "$ref": "#/components/schemas/WsAlertTraderNewTradeEvent" + }, + { + "$ref": "#/components/schemas/WsAlertTraderGlobalPnlEvent" + }, + { + "$ref": "#/components/schemas/WsAlertTraderMarketPnlEvent" + }, + { + "$ref": "#/components/schemas/WsAlertTraderEventPnlEvent" + }, + { + "$ref": "#/components/schemas/WsAlertConditionMetricsEvent" + }, + { + "$ref": "#/components/schemas/WsAlertEventMetricsEvent" + }, + { + "$ref": "#/components/schemas/WsAlertPositionMetricsEvent" + }, + { + "$ref": "#/components/schemas/WsAlertMarketVolumeMilestoneEvent" + }, + { + "$ref": "#/components/schemas/WsAlertEventVolumeMilestoneEvent" + }, + { + "$ref": "#/components/schemas/WsAlertPositionVolumeMilestoneEvent" + }, + { + "$ref": "#/components/schemas/WsAlertProbabilitySpikeEvent" + }, + { + "$ref": "#/components/schemas/WsAlertPriceSpikeEvent" + }, + { + "$ref": "#/components/schemas/WsAlertMarketVolumeSpikeEvent" + }, + { + "$ref": "#/components/schemas/WsAlertEventVolumeSpikeEvent" + }, + { + "$ref": "#/components/schemas/WsAlertPositionVolumeSpikeEvent" + }, + { + "$ref": "#/components/schemas/WsAlertCloseToBondEvent" + }, + { + "$ref": "#/components/schemas/WsAlertMarketCreatedEvent" + }, + { + "$ref": "#/components/schemas/WsAlertAssetPriceTickEvent" + }, + { + "$ref": "#/components/schemas/WsAlertAssetPriceWindowUpdateEvent" + } + ], + "discriminator": { + "propertyName": "event" + } } }, "securitySchemes": { diff --git a/package.json b/package.json index a345230..a729315 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@structbuild/sdk", - "version": "0.2.8", + "version": "0.2.9", "type": "module", "main": "./dist/index.cjs", "module": "./dist/index.js", @@ -32,7 +32,7 @@ "generate:polymarket": "openapi-typescript openapi/polymarket.json -o src/generated/polymarket.ts", "fetch-spec:webhooks": "curl -s -o openapi/webhooks.json https://api.struct.to/webhookopenapi.json", "generate:webhooks": "openapi-typescript openapi/webhooks.json -o src/generated/webhooks.ts", - "fetch-spec:ws": "curl -s -o openapi/ws.json https://staging-api.struct.to/asyncapi.json", + "fetch-spec:ws": "curl -s --compressed -o openapi/ws.json https://staging-api.struct.to/asyncapi.json", "generate:ws": "bun run scripts/generate-ws-types.ts" }, "devDependencies": { diff --git a/scripts/check-routes.ts b/scripts/check-routes.ts index b363470..e6f2b99 100644 --- a/scripts/check-routes.ts +++ b/scripts/check-routes.ts @@ -116,6 +116,7 @@ async function getExportedSchemas(typesContent: string): Promise> { for (const m of typesContent.matchAll(/Schemas\["(\w+)"\]/g)) exported.add(m[1]); for (const m of typesContent.matchAll(/WebhookSchemas\["(\w+)"\]/g)) exported.add(m[1]); for (const m of typesContent.matchAll(/WsSchemas\["(\w+)"\]/g)) exported.add(m[1]); + for (const m of typesContent.matchAll(/components\["schemas"\]\["(\w+)"\]/g)) exported.add(m[1]); for (const m of typesContent.matchAll(/export type (\w+)\s*=/g)) exported.add(m[1]); for (const m of typesContent.matchAll(/export interface (\w+)/g)) exported.add(m[1]); return exported; @@ -144,7 +145,8 @@ let hasErrors = false; const typesContent = await readFile(TYPES_FILE, "utf-8"); const wsTypesContent = await readFile(join(import.meta.dirname, "../src/types/ws.ts"), "utf-8"); -const combinedTypesContent = typesContent + "\n" + wsTypesContent; +const wsGeneratedContent = await readFile(join(import.meta.dirname, "../src/generated/ws.ts"), "utf-8"); +const combinedTypesContent = typesContent + "\n" + wsTypesContent + "\n" + wsGeneratedContent; const exportedSchemas = await getExportedSchemas(combinedTypesContent); for (const config of specs) { diff --git a/scripts/generate-ws-types.ts b/scripts/generate-ws-types.ts index faddc34..064787c 100644 --- a/scripts/generate-ws-types.ts +++ b/scripts/generate-ws-types.ts @@ -6,13 +6,96 @@ const asyncapiPath = join(import.meta.dirname, "../openapi/ws.json"); const outputPath = join(import.meta.dirname, "../src/generated/ws.ts"); const asyncapi = JSON.parse(await readFile(asyncapiPath, "utf-8")); +const schemas = asyncapi.components.schemas; + +for (const schema of Object.values(schemas) as Array>) { + const required = new Set((schema.required as string[]) ?? []); + const properties = schema.properties as Record> | undefined; + if (!properties) continue; + for (const [propName, prop] of Object.entries(properties)) { + if ("default" in prop && !required.has(propName)) { + delete prop.default; + } + } +} + +const ALERT_DISCRIMINATED_SCHEMAS = [ + "WsAlertSubscribeMessage", + "WsAlertUnsubscribeMessage", + "WsAlertEventPayload", +] as const; + +for (const parentName of ALERT_DISCRIMINATED_SCHEMAS) { + const parent = schemas[parentName]; + if (!parent?.oneOf || !parent?.discriminator) continue; + + const mapping: Record = {}; + for (const variant of parent.oneOf) { + const ref = variant.$ref as string | undefined; + if (!ref) continue; + const schemaName = ref.split("/").pop()!; + const variantSchema = schemas[schemaName]; + + let eventValue: string | undefined; + const allOf = variantSchema?.allOf as Array> | undefined; + if (allOf) { + for (const part of allOf) { + const props = part.properties as Record | undefined; + eventValue ??= props?.event?.enum?.[0]; + } + } + eventValue ??= variantSchema?.properties?.event?.enum?.[0]; + + if (eventValue) { + mapping[eventValue] = ref; + } + } + + parent.discriminator.mapping = mapping; +} const ast = await openapiTS({ openapi: "3.1.0", info: asyncapi.info, paths: {}, - components: { schemas: asyncapi.components.schemas }, + components: { schemas }, }); -await writeFile(outputPath, astToString(ast)); +let output = astToString(ast); + +const eventNames: string[] = []; +const subscribeEntries: string[] = []; +const eventDataEntries: string[] = []; + +const subscribeMapping = schemas.WsAlertSubscribeMessage?.discriminator?.mapping as Record | undefined; +const eventMapping = schemas.WsAlertEventPayload?.discriminator?.mapping as Record | undefined; + +if (subscribeMapping) { + for (const [eventName, ref] of Object.entries(subscribeMapping)) { + const schemaName = ref.split("/").pop()!; + subscribeEntries.push(`\t${eventName}: components["schemas"]["${schemaName}"];`); + } +} + +if (eventMapping) { + for (const [eventName, ref] of Object.entries(eventMapping)) { + const schemaName = ref.split("/").pop()!; + eventNames.push(eventName); + + const eventSchema = schemas[schemaName]; + const dataRef = eventSchema?.properties?.data?.$ref as string | undefined; + const dataSchemaName = dataRef?.split("/").pop(); + if (dataSchemaName) { + eventDataEntries.push(`\t${eventName}: components["schemas"]["${dataSchemaName}"];`); + } + } +} + +if (subscribeEntries.length > 0) { + output += `\nexport interface WsAlertSubscribeMap {\n${subscribeEntries.join("\n")}\n}\n`; + output += `\nexport interface WsAlertEventDataMap {\n${eventDataEntries.join("\n")}\n}\n`; + output += `\nexport type WsAlertEventName = keyof WsAlertSubscribeMap;\n`; +} + +await writeFile(outputPath, output); console.log("✓ Generated WS types from AsyncAPI spec"); diff --git a/src/generated/polymarket.ts b/src/generated/polymarket.ts index 89f26bf..ce50ad0 100644 --- a/src/generated/polymarket.ts +++ b/src/generated/polymarket.ts @@ -104,7 +104,7 @@ export interface paths { patch?: never; trace?: never; }; - "/polymarket/events/slug/{slug}": { + "/polymarket/events/slug/{event_slug}": { parameters: { query?: never; header?: never; @@ -404,7 +404,7 @@ export interface paths { patch?: never; trace?: never; }; - "/polymarket/market/slug/{slug}": { + "/polymarket/market/slug/{market_slug}": { parameters: { query?: never; header?: never; @@ -951,6 +951,8 @@ export interface components { }; /** @enum {string} */ CandlestickResolution: "1" | "5" | "15" | "30" | "60" | "240" | "D" | "1D"; + /** @enum {string} */ + ChartResolution: "1H" | "6H" | "1D" | "1W" | "1M" | "ALL"; /** @description CLOB reward (public API format) */ ClobReward: { id: string; @@ -962,6 +964,18 @@ export interface components { rewards_daily_rate?: number | null; start_date?: string | null; end_date?: string | null; + /** Format: double */ + rewards_max_spread?: number | null; + /** Format: double */ + rewards_min_size?: number | null; + /** Format: double */ + native_daily_rate?: number | null; + /** Format: double */ + sponsored_daily_rate?: number | null; + /** Format: double */ + total_daily_rate?: number | null; + /** Format: int32 */ + sponsors_count?: number | null; }; /** @description Response type for condition metrics query */ ConditionMetricsResponse: { @@ -1770,6 +1784,8 @@ export interface components { }; /** @enum {string} */ PositionPnlSortBy: "realized_pnl_usd" | "buy_usd" | "sell_usd" | "redemption_usd" | "total_buys" | "total_sells" | "total_shares_bought" | "total_shares_sold" | "avg_entry_price" | "avg_exit_price" | "total_fees" | "first_trade_at" | "last_trade_at" | "current_value" | "realized_pnl_pct" | "title"; + /** @enum {string} */ + PositionStatus: "open" | "closed"; PositionVolumeChartResponse: { volumes: components["schemas"]["PositionVolumeDataPoint"][]; has_more: boolean; @@ -1826,6 +1842,7 @@ export interface components { question?: string | null; image_url?: string | null; slug?: string | null; + event_slug?: string | null; /** Format: double */ usd_amount: number; /** Format: double */ @@ -1934,7 +1951,7 @@ export interface components { /** @enum {string} */ TradeSide: "0" | "1"; /** @enum {string} */ - TradeType: "0" | "1" | "2" | "4" | "6"; + TradeType: "0" | "1" | "2" | "3" | "4" | "5" | "6"; /** * @description Trader profile info embedded in API responses * @@ -2439,7 +2456,7 @@ export interface operations { header?: never; path: { /** @description Event slug */ - slug: string; + event_slug: string; }; cookie?: never; }; @@ -2721,6 +2738,8 @@ export interface operations { limit?: number; /** @description Cursor-based pagination key */ pagination_key?: string; + /** @description Only return markets that have CLOB rewards (default: false) */ + has_rewards?: boolean; /** @description Return truncated response optimized for AI consumers (default: false) */ ai?: boolean; }; @@ -3011,7 +3030,7 @@ export interface operations { header?: never; path: { /** @description Market slug (e.g. `will-trump-win`) */ - slug: string; + market_slug: string; }; cookie?: never; }; @@ -3098,8 +3117,8 @@ export interface operations { outcome?: string; /** @description Outcome index: 0 (Yes), 1 (No) */ outcome_index?: components["schemas"]["OutcomeIndex"]; - /** @description Trade type: 0 (OrderFilled), 1 (Redemption), 2 (Merge) */ - trade_type?: components["schemas"]["TradeType"]; + /** @description Comma-separated trade types: OrderFilled, Redemption, Merge, Split, Cancelled, PositionsConverted, OrdersMatched */ + trade_types?: string; /** @description Min USD amount */ min_usd_amount?: number; /** @description Max USD amount */ @@ -3999,8 +4018,8 @@ export interface operations { outcome?: string; /** @description Outcome index: 0 (Yes), 1 (No) */ outcome_index?: components["schemas"]["OutcomeIndex"]; - /** @description Trade type: 0 (OrderFilled), 1 (Redemption), 2 (Merge) */ - trade_type?: components["schemas"]["TradeType"]; + /** @description Comma-separated trade types: OrderFilled, Redemption, Merge, Split, Cancelled, PositionsConverted, OrdersMatched */ + trade_types?: string; /** @description Min USD amount */ min_usd_amount?: number; /** @description Max USD amount */ diff --git a/src/generated/webhooks.ts b/src/generated/webhooks.ts index fc67585..9f8c377 100644 --- a/src/generated/webhooks.ts +++ b/src/generated/webhooks.ts @@ -2140,7 +2140,7 @@ export interface components { position_outcome_indices?: number[]; /** @description When `true`, suppress webhooks for short-term "updown" markets. Default: `false`. */ exclude_shortterm_markets?: boolean; - }; + } | unknown | unknown; /** @description Subscription filters for the `market_created` event. All fields are optional. */ MarketCreatedFilters: { /** @description Restrict to markets with these tags or category names (case-insensitive match). */ diff --git a/src/generated/ws.ts b/src/generated/ws.ts index 3d61ebb..fa6b219 100644 --- a/src/generated/ws.ts +++ b/src/generated/ws.ts @@ -2,94 +2,62 @@ export type paths = Record; export type webhooks = Record; export interface components { schemas: { - /** @description Server-pushed event: a trade executed by a tracked wallet. Envelope type: "wallet_tracking_alert". */ - WalletTrackingAlertEvent: { - /** @description True = buy, false = sell */ - is_buy: boolean; - /** @description Trader EVM wallet address (lowercase) */ - trader: string; - /** @description 64-char hex condition ID */ - condition_id?: string | null; - /** @description ERC-1155 outcome token ID (decimal string) */ - position_id: string; - /** @description USD value of the trade (decimal string, 6dp) */ - usd_amount: string; - /** @description Number of shares traded (decimal string, 6dp) */ - shares_amount: string; - /** @description Trade price (0–1) */ - price: number; - /** @description Implied probability (0–1) */ - probability?: number | null; - /** @description Market metadata — null when enrichment is unavailable */ - metadata?: components["schemas"]["PredictionMarketMetadata"] | null; - /** - * Format: int64 - * @description Unix seconds - */ - confirmed_at: number; + /** @description Subscription filters for the `asset_price_window_update` event. All fields are optional. */ + AssetPriceWindowUpdateFilters: { + /** @description Restrict to these crypto assets. Empty = all assets. */ + asset_symbols?: ("BTC" | "ETH" | "SOL" | "XRP" | "DOGE" | "BNB" | "HYPE")[]; + /** @description Restrict to these candle sizes. Empty = all sizes. */ + timeframes?: ("5m" | "15m" | "1h" | "4h" | "1d" | "24h")[]; }; - /** @description Market metadata enrichment attached to wallet tracking alerts */ - PredictionMarketMetadata: { - /** @description Market slug */ - slug?: string | null; - /** @description Market question text */ - question?: string | null; - /** @description Outcome name (e.g. "Yes") */ - outcome?: string | null; - outcome_index?: number | null; - image_url?: string | null; + /** @description Subscription filters for the `asset_price_tick` event. All fields are optional. */ + AssetPriceTickFilters: { + /** @description Restrict to these crypto assets. Empty = all assets. */ + asset_symbols?: ("BTC" | "ETH" | "SOL" | "XRP" | "DOGE" | "BNB" | "HYPE")[]; }; - /** @description Server-pushed event: full CLOB orderbook snapshot for an outcome token. Envelope type: "order_book_update". Delivered whenever the book changes for a subscribed condition or position. */ - OrderBookUpdateEvent: { - /** @description Hex token ID (position / outcome token) */ - asset_id: string; - /** @description Condition ID (hex) */ - market: string; - /** @description Bid levels sorted best-first (highest price first) */ - bids: components["schemas"]["OrderBookLevel"][]; - /** @description Ask levels sorted best-first (lowest price first) */ - asks: components["schemas"]["OrderBookLevel"][]; - /** - * Format: int64 - * @description Unix milliseconds from CLOB message - */ - timestamp: number; - /** @description Orderbook content hash — identical hash means no change */ - hash: string; - /** @description Best bid price (0–1) */ - best_bid?: number | null; - /** @description Best ask price (0–1) */ - best_ask?: number | null; - /** @description (best_bid + best_ask) / 2 */ - mid_price?: number | null; - /** @description best_ask − best_bid */ - spread?: number | null; - /** @description Total USD value of all bid levels */ - bid_liquidity_usd?: number | null; - /** @description Total USD value of all ask levels */ - ask_liquidity_usd?: number | null; - /** @description Number of bid price levels */ - bid_levels?: number | null; - /** @description Number of ask price levels */ - ask_levels?: number | null; + /** @description Subscription filters for the `market_created` event. All fields are optional. */ + MarketCreatedFilters: { + /** @description Restrict to markets with these tags or category names (case-insensitive match). */ + tags?: string[]; + /** @description Restrict to these specific markets. */ + condition_ids?: string[]; + /** @description Restrict to markets belonging to these events. */ + event_slugs?: string[]; + /** @description When `true`, suppress webhooks for short-term "updown" markets (event slugs containing `updown`). Default: `false`. */ + exclude_shortterm_markets?: boolean; }; - /** @description A single price level: [price_string, size_string] */ - OrderBookLevel: string[]; - /** @description Server-pushed event: MATIC native balance change for a wallet. Envelope type: "matic_update". Only delivered when `include_matic: true`. */ - MaticUpdateEvent: { - /** @description Wallet address (0x-prefixed hex) */ - address: string; - /** @description Native token address — omitted when not available */ - token_address?: string; - /** @description Current MATIC balance (decimal string) — omitted when not available */ - balance?: string; - /** Format: uint64 */ - block_number: number; - /** - * Format: int64 - * @description Unix seconds - */ - updated_at: number; + /** @description Subscription filters for the `close_to_bond` event. At least one of `min_probability` or `max_probability` is required. */ + CloseToBondFilters: { + /** @description Trigger when the YES outcome price is ≥ this value (e.g. 0.95 for 95% certainty). At least one of `min_probability` or `max_probability` must be set. */ + min_probability?: number; + /** @description Trigger when the YES outcome price is ≤ this value (e.g. 0.05 for near-certain NO). */ + max_probability?: number; + /** @description Restrict to these markets. */ + condition_ids?: string[]; + /** @description Restrict to these outcome token IDs. */ + position_ids?: string[]; + /** @description Restrict to markets in these events. */ + event_slugs?: string[]; + /** @description Restrict to these outcome names (e.g. ["Yes", "No"]). */ + outcomes?: string[]; + /** @description Restrict by outcome index. 0 = Yes/Up, 1 = No. Position 0 usually represents the Up/Yes side in binary markets. */ + position_outcome_indices?: number[]; + /** @description When `true`, suppress webhooks for short-term "updown" markets. Default: `false`. */ + exclude_shortterm_markets?: boolean; + } | unknown | unknown; + /** @description Subscription filters for the `position_volume_spike` event. `spike_ratio` is required. */ + PositionVolumeSpikeFilters: { + /** @description **Required.** Multiplier threshold (must be > 1.0). Fires when current volume >= snapshot × ratio. */ + spike_ratio: number; + /** @description Force snapshot reset after this many seconds (max 600 / 10 minutes). */ + window_secs?: number; + /** @description Restrict to these outcome token IDs. */ + position_ids?: string[]; + /** @description Restrict to positions within these markets. */ + condition_ids?: string[]; + /** @description Restrict to these outcome names. */ + outcomes?: string[]; + /** @description Restrict to these aggregation windows. */ + timeframes?: ("1m" | "5m" | "30m" | "1h" | "6h" | "1d" | "24h" | "7d" | "30d")[]; }; /** @description Subscribe to the trades stream. At least one filter field must be non-empty. */ TradesStreamSubscribeMessage: { @@ -103,6 +71,8 @@ export interface components { event_slugs?: string[]; /** @description ERC-1155 outcome token IDs (decimal or hex strings) */ position_ids?: string[]; + /** @description Only receive trades of these types. Empty array = all types. */ + trade_types?: ("OrderFilled" | "Redemption" | "Merge" | "Split" | "Cancelled" | "PositionsConverted" | "OrdersMatched")[]; }; /** @description Server acknowledgement for a trades stream subscription */ TradesStreamSubscribeResponse: { @@ -110,155 +80,10 @@ export interface components { market_slugs?: string[]; event_slugs?: string[]; position_ids?: string[]; - /** @description Filter values that were rejected (invalid format) */ - rejected?: string[]; - }; - /** @description Subscribe to the asset prices stream. Empty asset_symbols = all assets. */ - AssetPricesSubscribeMessage: { - /** @enum {string} */ - action: "subscribe" | "unsubscribe_all"; - /** @description Uppercase asset symbols (e.g. "BTC", "ETH"). Empty = subscribe to all. */ - asset_symbols?: string[]; - }; - /** @description Server acknowledgement for an asset prices subscription */ - AssetPricesSubscribeResponse: { - /** @description Accepted symbols. Empty array means subscribed to all symbols. */ - asset_symbols?: string[]; - }; - /** @description Subscribe to the asset window updates stream. At least one of asset_symbols or timeframes must be non-empty. */ - AssetWindowUpdatesSubscribeMessage: { - /** @enum {string} */ - action: "subscribe" | "unsubscribe_all"; - /** @description Uppercase asset symbols (e.g. "BTC", "ETH") */ - asset_symbols?: string[]; - /** @description Candle sizes to filter by. "1d" and "24h" are treated as equivalent. */ - timeframes?: ("5m" | "15m" | "1h" | "4h" | "1d" | "24h")[]; - }; - /** @description Server acknowledgement for an asset window updates subscription */ - AssetWindowUpdatesSubscribeResponse: { - asset_symbols?: string[]; - timeframes?: string[]; - /** @description Set if the subscription was rejected (e.g. no filters provided) */ - error?: string | null; - }; - /** @description Subscribe to the market metrics stream. condition_ids is required and must be non-empty. */ - MarketMetricsSubscribeMessage: { - /** @enum {string} */ - action: "subscribe" | "unsubscribe_all"; - /** @description 64-char hex condition IDs (with or without 0x prefix) */ - condition_ids: string[]; - }; - /** @description Server acknowledgement for a market metrics subscription */ - MarketMetricsSubscribeResponse: { - condition_ids?: string[]; - /** @description Condition IDs that were rejected (invalid format) */ - rejected?: string[]; - /** @description Set if the entire subscription was rejected */ - error?: string | null; - }; - /** @description Subscribe to the event metrics stream. event_slugs is required and must be non-empty. */ - EventMetricsSubscribeMessage: { - /** @enum {string} */ - action: "subscribe" | "unsubscribe_all"; - /** @description Event slugs (lowercase) */ - event_slugs: string[]; - }; - /** @description Server acknowledgement for an event metrics subscription */ - EventMetricsSubscribeResponse: { - event_slugs?: string[]; - rejected?: string[]; - error?: string | null; - }; - /** @description Subscribe to the position metrics stream. position_ids is required and must be non-empty. */ - PositionMetricsSubscribeMessage: { - /** @enum {string} */ - action: "subscribe" | "unsubscribe_all"; - /** @description ERC-1155 outcome token IDs (decimal or hex strings) */ - position_ids: string[]; - }; - /** @description Server acknowledgement for a position metrics subscription */ - PositionMetricsSubscribeResponse: { - position_ids?: string[]; - rejected?: string[]; - error?: string | null; - }; - /** @description Subscribe to the trader PnL stream. traders is required and must be non-empty. */ - TraderPnlSubscribeMessage: { - /** @enum {string} */ - action: "subscribe" | "unsubscribe_all"; - /** @description EVM wallet addresses */ - traders: string[]; - }; - /** @description Server acknowledgement for a trader PnL subscription */ - TraderPnlSubscribeResponse: { - traders?: string[]; - rejected?: string[]; - error?: string | null; - }; - /** @description Subscribe to the trader positions stream. traders is required and must be non-empty. */ - TraderPositionsSubscribeMessage: { - /** @enum {string} */ - action: "subscribe" | "unsubscribe_all"; - /** @description EVM wallet addresses */ - traders: string[]; - }; - /** @description Server acknowledgement for a trader positions subscription */ - TraderPositionsSubscribeResponse: { - traders?: string[]; - rejected?: string[]; - error?: string | null; - }; - /** @description Subscribe to the accounts stream. `wallets` is required. Share balance updates (`accounts_update`) are always delivered. Set `include_usdce` or `include_matic` to also receive those balance streams. */ - AccountsSubscribeMessage: { - /** @enum {string} */ - action: "subscribe" | "unsubscribe_all"; - /** @description EVM wallet addresses */ - wallets: string[]; - /** - * @description Also stream USDCe collateral balance updates for subscribed wallets - * @default false - */ - include_usdce: boolean; - /** - * @description Also stream MATIC gas balance updates for subscribed wallets - * @default false - */ - include_matic: boolean; - }; - /** @description Server acknowledgement for an accounts subscription */ - AccountsSubscribeResponse: { - wallets?: string[]; - /** @description Addresses rejected (invalid format) */ - rejected?: string[]; - include_usdce?: boolean; - include_matic?: boolean; - error?: string | null; - }; - /** @description Subscribe to the order book stream. At least one filter is required. Maximum 500 combined condition_ids + position_ids per client. No `type` field is needed — the server routes by room_id. */ - OrderBookSubscribeMessage: { - /** @enum {string} */ - action: "subscribe" | "unsubscribe_all"; - /** @description Condition IDs (markets). All positions within each market are delivered. */ - condition_ids?: string[]; - /** @description Token / asset IDs (individual outcome positions, hex strings). */ - position_ids?: string[]; - }; - /** @description Server acknowledgement for an order book subscription. Envelope type: "order_book_stream_subscribe_response". */ - OrderBookSubscribeResponse: { - /** @description Accepted condition IDs */ - condition_ids?: string[]; - /** @description Accepted position IDs */ - position_ids?: string[]; - /** @description Filter values that were rejected (invalid format or limit exceeded) */ + trade_types?: string[]; + /** @description Filter values that were rejected (invalid format or unknown trade type) */ rejected?: string[]; }; - /** @description Subscribe to wallet trade alerts. wallet_addresses is required. */ - WalletTrackingSubscribeMessage: { - /** @enum {string} */ - action: "subscribe"; - /** @description EVM wallet addresses to track */ - wallet_addresses: string[]; - }; /** @description Server-pushed event: a matched trade on a subscribed market/position/event/slug. Envelope type: "trade_stream_update". */ TradeStreamEvent: { /** @description Trade ID */ @@ -284,7 +109,7 @@ export interface components { trader: string; /** @description Order taker wallet address */ taker: string; - /** @description "Buy" or "Sell" */ + /** @description "Buy" or "Sell" (null for non-trade operations like Redemption, Merge, Split) */ side?: string | null; /** @description 64-char hex condition ID */ condition_id?: string | null; @@ -321,6 +146,18 @@ export interface components { is_bot?: boolean; bot_reason?: string | null; }; + /** @description Subscribe to the asset prices stream. Empty asset_symbols = all assets. */ + AssetPricesSubscribeMessage: { + /** @enum {string} */ + action: "subscribe" | "unsubscribe_all"; + /** @description Uppercase asset symbols (e.g. "BTC", "ETH"). Empty = subscribe to all. */ + asset_symbols?: string[]; + }; + /** @description Server acknowledgement for an asset prices subscription */ + AssetPricesSubscribeResponse: { + /** @description Accepted symbols. Empty array means subscribed to all symbols. */ + asset_symbols?: string[]; + }; /** @description Server-pushed event: a crypto-asset price tick. Envelope type: "asset_price_tick". */ AssetPriceTickEvent: { /** @description Always "asset_price_tick" */ @@ -370,16 +207,47 @@ export interface components { */ published_at: number; }; - /** @description Server-pushed event from the polymarket_asset_window_updates room. Same payload as AssetPriceWindowUpdateEvent. Envelope type: "asset_price_window_update". */ - AssetWindowUpdateEvent: components["schemas"]["AssetPriceWindowUpdateEvent"]; - /** @description Server-pushed event: metrics update for one timeframe of a condition. Envelope type: "market_metrics_update". One event is emitted per timeframe window on each update. */ - MarketMetricsEvent: { - /** @description 64-char hex condition ID */ - condition_id: string; + /** @description Subscribe to the asset window updates stream. At least one of asset_symbols or timeframes must be non-empty. */ + AssetWindowUpdatesSubscribeMessage: { /** @enum {string} */ - timeframe: "1m" | "5m" | "30m" | "1h" | "6h" | "24h" | "7d" | "30d"; - /** - * Format: int64 + action: "subscribe" | "unsubscribe_all"; + /** @description Uppercase asset symbols (e.g. "BTC", "ETH") */ + asset_symbols?: string[]; + /** @description Candle sizes to filter by. "1d" and "24h" are treated as equivalent. */ + timeframes?: ("5m" | "15m" | "1h" | "4h" | "1d" | "24h")[]; + }; + /** @description Server acknowledgement for an asset window updates subscription */ + AssetWindowUpdatesSubscribeResponse: { + asset_symbols?: string[]; + timeframes?: string[]; + /** @description Set if the subscription was rejected (e.g. no filters provided) */ + error?: string | null; + }; + /** @description Server-pushed event from the polymarket_asset_window_updates room. Same payload as AssetPriceWindowUpdateEvent. Envelope type: "asset_price_window_update". */ + AssetWindowUpdateEvent: components["schemas"]["AssetPriceWindowUpdateEvent"]; + /** @description Subscribe to the market metrics stream. condition_ids is required and must be non-empty. */ + MarketMetricsSubscribeMessage: { + /** @enum {string} */ + action: "subscribe" | "unsubscribe_all"; + /** @description 64-char hex condition IDs (with or without 0x prefix) */ + condition_ids: string[]; + }; + /** @description Server acknowledgement for a market metrics subscription */ + MarketMetricsSubscribeResponse: { + condition_ids?: string[]; + /** @description Condition IDs that were rejected (invalid format) */ + rejected?: string[]; + /** @description Set if the entire subscription was rejected */ + error?: string | null; + }; + /** @description Server-pushed event: metrics update for one timeframe of a condition. Envelope type: "market_metrics_update". One event is emitted per timeframe window on each update. */ + MarketMetricsEvent: { + /** @description 64-char hex condition ID */ + condition_id: string; + /** @enum {string} */ + timeframe: "1m" | "5m" | "30m" | "1h" | "6h" | "24h" | "7d" | "30d"; + /** + * Format: int64 * @description Optional event timestamp (Unix seconds) */ timestamp?: number | null; @@ -407,6 +275,19 @@ export interface components { /** Format: int64 */ latest_block: number; }; + /** @description Subscribe to the event metrics stream. event_slugs is required and must be non-empty. */ + EventMetricsSubscribeMessage: { + /** @enum {string} */ + action: "subscribe" | "unsubscribe_all"; + /** @description Event slugs (lowercase) */ + event_slugs: string[]; + }; + /** @description Server acknowledgement for an event metrics subscription */ + EventMetricsSubscribeResponse: { + event_slugs?: string[]; + rejected?: string[]; + error?: string | null; + }; /** @description Server-pushed event: aggregated metrics update for one timeframe of an event. Envelope type: "event_metrics_update". One event is emitted per timeframe window on each update. */ EventMetricsEvent: { event_slug: string; @@ -431,6 +312,19 @@ export interface components { /** Format: int64 */ latest_block: number; }; + /** @description Subscribe to the position metrics stream. position_ids is required and must be non-empty. */ + PositionMetricsSubscribeMessage: { + /** @enum {string} */ + action: "subscribe" | "unsubscribe_all"; + /** @description ERC-1155 outcome token IDs (decimal or hex strings) */ + position_ids: string[]; + }; + /** @description Server acknowledgement for a position metrics subscription */ + PositionMetricsSubscribeResponse: { + position_ids?: string[]; + rejected?: string[]; + error?: string | null; + }; /** @description Server-pushed event: metrics update for one timeframe of an outcome token. Envelope type: "position_metrics_update". One event is emitted per timeframe window on each update. */ PositionMetricsEvent: { /** @description 64-char hex condition ID */ @@ -485,6 +379,19 @@ export interface components { /** Format: int64 */ latest_block: number; }; + /** @description Subscribe to the trader PnL stream. traders is required and must be non-empty. */ + TraderPnlSubscribeMessage: { + /** @enum {string} */ + action: "subscribe" | "unsubscribe_all"; + /** @description EVM wallet addresses */ + traders: string[]; + }; + /** @description Server acknowledgement for a trader PnL subscription */ + TraderPnlSubscribeResponse: { + traders?: string[]; + rejected?: string[]; + error?: string | null; + }; /** @description Server-pushed event: global (portfolio-level) PnL update for a trader. Envelope type: "trader_global_pnl_update". */ TraderGlobalPnlEvent: { /** @description Trader EVM wallet address */ @@ -623,6 +530,19 @@ export interface components { /** @description "1d", "7d", "30d", or "lifetime" */ timeframe?: string | null; }; + /** @description Subscribe to the trader positions stream. traders is required and must be non-empty. */ + TraderPositionsSubscribeMessage: { + /** @enum {string} */ + action: "subscribe" | "unsubscribe_all"; + /** @description EVM wallet addresses */ + traders: string[]; + }; + /** @description Server acknowledgement for a trader positions subscription */ + TraderPositionsSubscribeResponse: { + traders?: string[]; + rejected?: string[]; + error?: string | null; + }; /** @description Server-pushed event: full position snapshot for a tracked trader. Envelope type: "trader_position_update". Pushed whenever a position's PnL changes in the database. */ TraderPositionUpdateEvent: { /** @description Trader EVM wallet address */ @@ -670,6 +590,26 @@ export interface components { /** @description Realized PnL as a percentage of cost basis */ realized_pnl_pct?: number | null; }; + /** @description Subscribe to the accounts stream. `wallets` is required. Share balance updates (`accounts_update`) are always delivered. Set `include_usdce` or `include_matic` to also receive those balance streams. */ + AccountsSubscribeMessage: { + /** @enum {string} */ + action: "subscribe" | "unsubscribe_all"; + /** @description EVM wallet addresses */ + wallets: string[]; + /** @description Also stream USDCe collateral balance updates for subscribed wallets */ + include_usdce?: boolean; + /** @description Also stream MATIC gas balance updates for subscribed wallets */ + include_matic?: boolean; + }; + /** @description Server acknowledgement for an accounts subscription */ + AccountsSubscribeResponse: { + wallets?: string[]; + /** @description Addresses rejected (invalid format) */ + rejected?: string[]; + include_usdce?: boolean; + include_matic?: boolean; + error?: string | null; + }; /** @description Server-pushed event: ERC-1155 outcome token balance change for a wallet. Envelope type: "accounts_update". */ AccountsUpdateEvent: { /** @description Wallet address */ @@ -706,12 +646,2710 @@ export interface components { */ updated_at: number; }; - }; - responses: never; - parameters: never; - requestBodies: never; - headers: never; - pathItems: never; -} -export type $defs = Record; -export type operations = Record; + /** @description Server-pushed event: MATIC native balance change for a wallet. Envelope type: "matic_update". Only delivered when `include_matic: true`. */ + MaticUpdateEvent: { + /** @description Wallet address (0x-prefixed hex) */ + address: string; + /** @description Native token address — omitted when not available */ + token_address?: string; + /** @description Current MATIC balance (decimal string) — omitted when not available */ + balance?: string; + /** Format: uint64 */ + block_number: number; + /** + * Format: int64 + * @description Unix seconds + */ + updated_at: number; + }; + /** @description Subscribe to the order book stream. At least one filter is required. Maximum 500 combined condition_ids + position_ids per client. No `type` field is needed — the server routes by room_id. */ + OrderBookSubscribeMessage: { + /** @enum {string} */ + action: "subscribe" | "unsubscribe_all"; + /** @description Condition IDs (markets). All positions within each market are delivered. */ + condition_ids?: string[]; + /** @description Token / asset IDs (individual outcome positions, hex strings). */ + position_ids?: string[]; + }; + /** @description Server acknowledgement for an order book subscription. Envelope type: "order_book_stream_subscribe_response". */ + OrderBookSubscribeResponse: { + /** @description Accepted condition IDs */ + condition_ids?: string[]; + /** @description Accepted position IDs */ + position_ids?: string[]; + /** @description Filter values that were rejected (invalid format or limit exceeded) */ + rejected?: string[]; + }; + /** @description A single price level: [price_string, size_string] */ + OrderBookLevel: string[]; + /** @description Server-pushed event: full CLOB orderbook snapshot for an outcome token. Envelope type: "order_book_update". Delivered whenever the book changes for a subscribed condition or position. */ + OrderBookUpdateEvent: { + /** @description Hex token ID (position / outcome token) */ + asset_id: string; + /** @description Condition ID (hex) */ + market: string; + /** @description Bid levels sorted best-first (highest price first) */ + bids: components["schemas"]["OrderBookLevel"][]; + /** @description Ask levels sorted best-first (lowest price first) */ + asks: components["schemas"]["OrderBookLevel"][]; + /** + * Format: int64 + * @description Unix milliseconds from CLOB message + */ + timestamp: number; + /** @description Orderbook content hash — identical hash means no change */ + hash: string; + /** @description Best bid price (0–1) */ + best_bid?: number | null; + /** @description Best ask price (0–1) */ + best_ask?: number | null; + /** @description (best_bid + best_ask) / 2 */ + mid_price?: number | null; + /** @description best_ask − best_bid */ + spread?: number | null; + /** @description Total USD value of all bid levels */ + bid_liquidity_usd?: number | null; + /** @description Total USD value of all ask levels */ + ask_liquidity_usd?: number | null; + /** @description Number of bid price levels */ + bid_levels?: number | null; + /** @description Number of ask price levels */ + ask_levels?: number | null; + }; + /** @description Subscribe to CLOB reward changes. Either provide specific condition_ids or set subscribe_all to true. */ + ClobRewardsSubscribeMessage: { + /** @enum {string} */ + action: "subscribe" | "unsubscribe_all"; + /** @description Condition IDs to watch for reward changes. */ + condition_ids?: string[]; + /** @description If true, receive ALL reward changes across all markets. Overrides condition_ids. */ + subscribe_all?: boolean; + }; + /** @description Server acknowledgement for a CLOB rewards subscription. Envelope type: "clob_rewards_stream_subscribe_response". */ + ClobRewardsSubscribeResponse: { + /** @description Accepted condition IDs */ + condition_ids?: string[]; + /** @description Whether subscribed to all changes */ + subscribe_all?: boolean; + /** @description Filter values that were rejected */ + rejected?: string[]; + }; + /** @description Server-pushed CLOB reward change event. Envelope type: "clob_rewards_update". */ + ClobRewardsUpdateEvent: { + /** + * @description Type of change + * @enum {string} + */ + event_type?: "added" | "removed" | "updated"; + /** @description Affected market condition ID */ + condition_id?: string; + /** @description Full reward state (null for 'removed' events) */ + reward?: { + condition_id?: string; + rewards_config?: { + id?: number; + /** @description Reward token address (e.g. USDC) */ + asset_address?: string; + /** Format: date */ + start_date?: string; + /** Format: date */ + end_date?: string; + /** @description Daily reward rate in USDC */ + rate_per_day?: number; + /** @description Cumulative rewards distributed */ + total_rewards?: number; + }[]; + /** @description Max spread to qualify for rewards */ + rewards_max_spread?: number | null; + /** @description Min order size to qualify for rewards */ + rewards_min_size?: number | null; + /** @description Native (non-sponsored) daily rate */ + native_daily_rate?: number | null; + /** @description Sponsored daily rate */ + sponsored_daily_rate?: number | null; + /** @description Combined daily rate (native + sponsored) */ + total_daily_rate?: number | null; + /** @description Number of sponsors */ + sponsors_count?: number | null; + } | null; + /** @description Unix timestamp in milliseconds */ + timestamp_ms?: number; + }; + /** @description Subscribe to wallet trade alerts. wallet_addresses is required. */ + WalletTrackingSubscribeMessage: { + /** @enum {string} */ + action: "subscribe"; + /** @description EVM wallet addresses to track */ + wallet_addresses: string[]; + }; + /** @description Server acknowledgement for a wallet tracking subscription */ + WalletTrackingSubscribeResponse: { + /** + * Format: uint64 + * @description Number of wallets successfully subscribed + */ + subscribed_count: number; + /** @description Addresses rejected (invalid format) */ + invalid_addresses?: string[]; + /** @description All wallet addresses currently tracked by this user */ + current_user_wallets: string[]; + /** + * Format: uint64 + * @description Total wallet count for this user + */ + total_wallets: number; + }; + /** @description Market metadata enrichment attached to wallet tracking alerts */ + PredictionMarketMetadata: { + /** @description Market slug */ + slug?: string | null; + /** @description Market question text */ + question?: string | null; + /** @description Outcome name (e.g. "Yes") */ + outcome?: string | null; + outcome_index?: number | null; + image_url?: string | null; + }; + /** @description Server-pushed event: a trade executed by a tracked wallet. Envelope type: "wallet_tracking_alert". */ + WalletTrackingAlertEvent: { + /** @description True = buy, false = sell */ + is_buy: boolean; + /** @description Trader EVM wallet address (lowercase) */ + trader: string; + /** @description 64-char hex condition ID */ + condition_id?: string | null; + /** @description ERC-1155 outcome token ID (decimal string) */ + position_id: string; + /** @description USD value of the trade (decimal string, 6dp) */ + usd_amount: string; + /** @description Number of shares traded (decimal string, 6dp) */ + shares_amount: string; + /** @description Trade price (0–1) */ + price: number; + /** @description Implied probability (0–1) */ + probability?: number | null; + /** @description Market metadata — null when enrichment is unavailable */ + metadata?: components["schemas"]["PredictionMarketMetadata"] | null; + /** + * Format: int64 + * @description Unix seconds + */ + confirmed_at: number; + }; + /** @description Payload delivered when a tracked trader executes their first-ever trade on Polymarket */ + FirstTradePayload: { + /** @description Limit-order maker wallet address (lowercase) */ + trader: string; + /** @description Order filler wallet address (lowercase) */ + taker: string; + /** @description ERC-1155 outcome token ID */ + position_id: string; + /** @description Parent market condition ID (0x-prefixed hex) */ + condition_id?: string | null; + /** @description Outcome name (e.g. "Yes", "No") */ + outcome?: string | null; + /** @description Outcome index: 0 = Yes/Up, 1 = No */ + outcome_index?: number | null; + /** @description Market question text */ + question?: string | null; + /** @description Market slug */ + market_slug?: string | null; + /** @description Parent event slug */ + event_slug?: string | null; + /** @description Unique trade identifier */ + trade_id: string; + /** @description Transaction hash */ + hash: string; + /** + * Format: int64 + * @description Block number + */ + block: number; + /** + * Format: int64 + * @description Block confirmation timestamp (Unix seconds) + */ + confirmed_at: number; + /** @description USD size of the trade (6 decimal places) */ + amount_usd: number; + /** @description Outcome shares traded (6 decimal places) */ + shares_amount: number; + /** @description Fee paid in USD (6 decimal places) */ + fee: number; + /** + * @description Trade direction + * @enum {string} + */ + side: "Buy" | "Sell"; + /** @description Outcome token price (0.0–1.0) */ + price: number; + /** @description Exchange identifier */ + exchange: string; + /** @description Trade type identifier */ + trade_type: string; + }; + /** @description Payload delivered when a trader places their first trade in a specific market (fires once per trader+market pair) */ + NewMarketPayload: { + /** @description Limit-order maker wallet address (lowercase) */ + trader: string; + /** @description Order filler wallet address (lowercase) */ + taker: string; + /** @description ERC-1155 outcome token ID */ + position_id: string; + /** @description Parent market condition ID */ + condition_id?: string | null; + /** @description Outcome name (e.g. "Yes", "No") */ + outcome?: string | null; + /** @description Outcome index: 0 = Yes/Up, 1 = No */ + outcome_index?: number | null; + /** @description Market question text */ + question?: string | null; + /** @description Market slug */ + market_slug?: string | null; + /** @description Parent event slug */ + event_slug?: string | null; + /** @description Unique trade identifier */ + trade_id: string; + /** @description Transaction hash */ + hash: string; + /** + * Format: int64 + * @description Block number + */ + block: number; + /** + * Format: int64 + * @description Block confirmation timestamp (Unix seconds) + */ + confirmed_at: number; + /** @description USD size of the trade (6 decimal places) */ + amount_usd: number; + /** @description Outcome shares traded (6 decimal places) */ + shares_amount: number; + /** @description Fee paid in USD (6 decimal places) */ + fee: number; + /** + * @description Trade direction + * @enum {string} + */ + side: "Buy" | "Sell"; + /** @description Outcome token price (0.0–1.0) */ + price: number; + /** @description Implied probability (0.0–1.0); null when outcome is unknown */ + probability?: number | null; + /** @description Exchange identifier */ + exchange: string; + /** @description Trade type identifier */ + trade_type: string; + }; + /** @description Payload delivered when a trade exceeds the configured size and probability thresholds */ + WhaleTradePayload: { + /** @description Limit-order maker wallet address (lowercase) */ + trader: string; + /** @description Order filler wallet address (lowercase) */ + taker: string; + /** @description ERC-1155 outcome token ID */ + position_id: string; + /** @description Parent market condition ID */ + condition_id?: string | null; + /** @description Outcome name (e.g. "Yes", "No") */ + outcome?: string | null; + /** @description Outcome index: 0 = Yes/Up, 1 = No */ + outcome_index?: number | null; + /** @description Market question text */ + question?: string | null; + /** @description Market slug */ + market_slug?: string | null; + /** @description Parent event slug */ + event_slug?: string | null; + /** @description Unique trade identifier */ + trade_id: string; + /** @description Transaction hash */ + hash: string; + /** + * Format: int64 + * @description Block number + */ + block: number; + /** + * Format: int64 + * @description Block confirmation timestamp (Unix seconds) + */ + confirmed_at: number; + /** @description USD size of the trade (6 decimal places) */ + amount_usd: number; + /** @description Outcome shares traded (6 decimal places) */ + shares_amount: number; + /** @description Fee paid in USD (6 decimal places) */ + fee: number; + /** + * @description Trade direction + * @enum {string} + */ + side: "Buy" | "Sell"; + /** @description Outcome token price (0.0–1.0) */ + price: number; + /** @description Implied probability (0.0–1.0); null when outcome is unknown */ + probability?: number | null; + /** @description Exchange identifier */ + exchange: string; + /** @description Trade type identifier */ + trade_type: string; + }; + /** @description Payload delivered on every order-filled trade */ + NewTradePayload: { + /** @description Limit-order maker wallet address (lowercase) */ + trader: string; + /** @description Order filler wallet address (lowercase) */ + taker: string; + /** @description ERC-1155 outcome token ID */ + position_id: string; + /** @description Parent market condition ID */ + condition_id?: string | null; + /** @description Outcome name (e.g. "Yes", "No") */ + outcome?: string | null; + /** @description Outcome index: 0 = Yes/Up, 1 = No */ + outcome_index?: number | null; + /** @description Market question text */ + question?: string | null; + /** @description Market slug */ + market_slug?: string | null; + /** @description Parent event slug */ + event_slug?: string | null; + /** @description Unique trade identifier */ + trade_id: string; + /** @description Transaction hash */ + hash: string; + /** + * Format: int64 + * @description Block number + */ + block: number; + /** + * Format: int64 + * @description Block confirmation timestamp (Unix seconds) + */ + confirmed_at: number; + /** @description USD size of the trade (6 decimal places) */ + amount_usd: number; + /** @description Outcome shares traded (6 decimal places) */ + shares_amount: number; + /** @description Fee paid in USD (6 decimal places) */ + fee: number; + /** + * @description Trade direction + * @enum {string} + */ + side: "Buy" | "Sell"; + /** @description Outcome token price (0.0–1.0) */ + price: number; + /** @description Implied probability (0.0–1.0); null when outcome is unknown */ + probability?: number | null; + /** @description Exchange identifier */ + exchange: string; + /** @description Trade type identifier */ + trade_type: string; + }; + /** @description Payload delivered when a trader's global PnL (across all markets) crosses a configured threshold */ + GlobalPnlPayload: { + /** @description Trader wallet address (lowercase) */ + trader?: string | null; + /** + * @description PnL aggregation window + * @enum {string} + */ + timeframe: "1d" | "7d" | "30d" | "lifetime"; + /** @description Realized PnL in USD (positive = profit, negative = loss) */ + realized_pnl_usd?: number | null; + /** + * Format: int64 + * @description Number of distinct events traded + */ + events_traded?: number | null; + /** + * Format: int64 + * @description Number of distinct markets traded + */ + markets_traded?: number | null; + /** + * Format: int64 + * @description Total buy transactions + */ + total_buys?: number | null; + /** + * Format: int64 + * @description Total sell transactions + */ + total_sells?: number | null; + /** + * Format: int64 + * @description Total redemption transactions + */ + total_redemptions?: number | null; + /** + * Format: int64 + * @description Total merge transactions + */ + total_merges?: number | null; + /** @description Total USD volume (buys + sells + redemptions + merges) */ + total_volume_usd?: number | null; + /** @description Total buy volume in USD */ + buy_volume_usd?: number | null; + /** @description Total sell volume in USD */ + sell_volume_usd?: number | null; + /** @description Total redemption volume in USD */ + redemption_volume_usd?: number | null; + /** @description Total merge volume in USD */ + merge_volume_usd?: number | null; + /** + * Format: int64 + * @description Number of markets where trader realised a profit + */ + markets_won?: number | null; + /** + * Format: int64 + * @description Number of markets where trader realised a loss + */ + markets_lost?: number | null; + /** @description Market win rate as a percentage (0.0–100.0) */ + market_win_rate_pct?: number | null; + /** @description Average PnL per market in USD */ + avg_pnl_per_market?: number | null; + /** @description Average PnL per trade in USD */ + avg_pnl_per_trade?: number | null; + /** @description Average hold time across all positions (seconds) */ + avg_hold_time_seconds?: number | null; + /** @description Total fees paid in USD */ + total_fees?: number | null; + /** @description Best single-trade PnL in USD */ + best_trade_pnl_usd?: number | null; + /** @description Condition ID of the best trade */ + best_trade_condition_id?: string | null; + /** + * Format: int64 + * @description Timestamp of the first trade (Unix seconds) + */ + first_trade_at?: number | null; + /** + * Format: int64 + * @description Timestamp of the most recent trade (Unix seconds) + */ + last_trade_at?: number | null; + }; + /** @description Payload delivered when a trader's per-market PnL crosses a configured threshold */ + MarketPnlPayload: { + /** @description Trader wallet address (lowercase) */ + trader?: string | null; + /** @description Market condition ID */ + condition_id?: string | null; + /** @description Parent event slug */ + event_slug?: string | null; + /** + * @description PnL aggregation window + * @enum {string} + */ + timeframe: "1d" | "7d" | "30d" | "lifetime"; + /** + * Format: int64 + * @description Number of distinct outcomes traded in this market + */ + outcomes_traded?: number | null; + /** Format: int64 */ + total_buys?: number | null; + /** Format: int64 */ + total_sells?: number | null; + /** Format: int64 */ + total_redemptions?: number | null; + /** Format: int64 */ + total_merges?: number | null; + /** @description Total buy volume in USD */ + buy_usd?: number | null; + /** @description Total sell volume in USD */ + sell_usd?: number | null; + /** @description Total redemption volume in USD */ + redemption_usd?: number | null; + /** @description Total merge volume in USD */ + merge_usd?: number | null; + /** @description Realized PnL in USD for this market */ + realized_pnl_usd?: number | null; + /** + * Format: int64 + * @description Number of outcomes with positive PnL + */ + winning_outcomes?: number | null; + /** @description Total fees paid in USD for this market */ + total_fees?: number | null; + /** + * Format: int64 + * @description Timestamp of first trade in market (Unix seconds) + */ + first_trade_at?: number | null; + /** + * Format: int64 + * @description Timestamp of most recent trade in market (Unix seconds) + */ + last_trade_at?: number | null; + }; + /** @description Payload delivered when a trader's per-event PnL crosses a configured threshold */ + EventPnlPayload: { + /** @description Trader wallet address (lowercase) */ + trader?: string | null; + /** @description Event slug */ + event_slug?: string | null; + /** + * @description PnL aggregation window + * @enum {string} + */ + timeframe: "1d" | "7d" | "30d" | "lifetime"; + /** + * Format: int64 + * @description Number of distinct markets traded in this event + */ + markets_traded?: number | null; + /** Format: int64 */ + outcomes_traded?: number | null; + /** Format: int64 */ + total_buys?: number | null; + /** Format: int64 */ + total_sells?: number | null; + /** Format: int64 */ + total_redemptions?: number | null; + /** Format: int64 */ + total_merges?: number | null; + /** @description Total volume in USD */ + total_volume_usd?: number | null; + buy_usd?: number | null; + sell_usd?: number | null; + redemption_usd?: number | null; + merge_usd?: number | null; + /** @description Realized PnL in USD for this event */ + realized_pnl_usd?: number | null; + /** Format: int64 */ + winning_markets?: number | null; + /** Format: int64 */ + losing_markets?: number | null; + total_fees?: number | null; + /** + * Format: int64 + * @description Unix seconds + */ + first_trade_at?: number | null; + /** + * Format: int64 + * @description Unix seconds + */ + last_trade_at?: number | null; + }; + /** @description Payload delivered when a market's volume or transaction metrics cross a configured threshold */ + ConditionMetricsPayload: { + /** @description Market condition ID */ + condition_id?: string | null; + /** @description Aggregation window (e.g. "1h", "24h") */ + timeframe?: string | null; + /** @description Total trading volume in USD for this timeframe */ + volume_usd?: number | null; + /** @description Total fees collected in USD */ + fees?: number | null; + /** + * Format: int64 + * @description Total number of transactions + */ + txns?: number | null; + /** + * Format: int64 + * @description Number of unique traders + */ + unique_traders?: number | null; + }; + /** @description Payload delivered when an event's aggregated volume or transaction metrics cross a configured threshold */ + EventMetricsPayload: { + /** @description Event slug */ + event_slug?: string | null; + /** @description Aggregation window (e.g. "1h", "24h") */ + timeframe?: string | null; + /** @description Total aggregated volume across all markets in the event (USD) */ + volume_usd?: number | null; + /** @description Total fees collected in USD */ + fees?: number | null; + /** + * Format: int64 + * @description Total number of transactions + */ + txns?: number | null; + /** + * Format: int64 + * @description Number of unique traders + */ + unique_traders?: number | null; + }; + /** @description Payload delivered when a position's volume or transaction metrics cross a configured threshold */ + PositionMetricsPayload: { + /** @description ERC-1155 outcome token ID */ + position_id?: string | null; + /** @description Outcome name (e.g. "Yes", "No") */ + outcome?: string | null; + /** + * Format: int16 + * @description Outcome index + */ + outcome_index?: number | null; + /** @description Aggregation window (e.g. "1h", "24h") */ + timeframe?: string | null; + /** @description Total trading volume in USD */ + volume_usd?: number | null; + /** @description Buy volume in USD */ + buy_volume_usd?: number | null; + /** @description Sell volume in USD */ + sell_volume_usd?: number | null; + /** @description Total fees in USD */ + fees?: number | null; + /** Format: int64 */ + txns?: number | null; + /** Format: int64 */ + buys?: number | null; + /** Format: int64 */ + sells?: number | null; + /** Format: int64 */ + unique_traders?: number | null; + price_open?: number | null; + price_close?: number | null; + price_high?: number | null; + price_low?: number | null; + probability_open?: number | null; + probability_close?: number | null; + probability_high?: number | null; + probability_low?: number | null; + }; + /** @description Payload delivered when a market's trading volume crosses a USD milestone in the specified timeframe */ + VolumeMilestonePayload: { + /** @description Market condition ID */ + condition_id: string; + /** @description Aggregation window that crossed the milestone (e.g. "1h", "24h") */ + timeframe: string; + /** @description The USD milestone amount that was crossed */ + milestone_usd: number; + /** @description Current volume at time of trigger (USD) */ + current_volume_usd: number; + /** @description Total fees in USD for this timeframe */ + fees: number; + /** + * Format: int64 + * @description Total transactions in this timeframe + */ + txns: number; + }; + /** @description Payload delivered when an event's aggregated trading volume crosses a USD milestone */ + EventVolumeMilestonePayload: { + /** @description Event slug */ + event_slug: string; + /** @description Aggregation window (e.g. "1h", "24h") */ + timeframe: string; + /** @description The USD milestone amount that was crossed */ + milestone_usd: number; + /** @description Current aggregated event volume at time of trigger (USD) */ + current_volume_usd: number; + /** @description Total fees in USD for this timeframe */ + fees: number; + /** + * Format: int64 + * @description Total transactions in this timeframe + */ + txns: number; + }; + /** @description Payload delivered when a position's trading volume crosses a USD milestone */ + PositionVolumeMilestonePayload: { + /** @description Parent market condition ID */ + condition_id?: string | null; + /** @description ERC-1155 outcome token ID */ + position_id: string; + /** @description Outcome name (e.g. "Yes", "No") */ + outcome?: string | null; + /** + * Format: int16 + * @description Outcome index + */ + outcome_index?: number | null; + /** @description Aggregation window (e.g. "1h", "24h") */ + timeframe: string; + /** @description The USD milestone amount that was crossed */ + milestone_usd: number; + /** @description Current position volume at time of trigger (USD) */ + current_volume_usd: number; + /** @description Buy volume in USD for this timeframe */ + buy_volume_usd: number; + /** @description Sell volume in USD for this timeframe */ + sell_volume_usd: number; + /** @description Total fees in USD */ + fees: number; + /** Format: int64 */ + txns: number; + /** Format: int64 */ + buys: number; + /** Format: int64 */ + sells: number; + }; + ProbabilitySpikePayload: { + /** @description Outcome token ID */ + position_id: string; + /** @description Market condition ID */ + condition_id?: string | null; + /** @description Event slug */ + event_slug?: string | null; + /** @description Outcome name (e.g. "Yes", "No") */ + outcome?: string | null; + /** + * Format: int16 + * @description Outcome index + */ + outcome_index?: number | null; + /** @description Probability at the start of the observation window (baseline snapshot, 0.0–1.0) */ + previous_probability: number; + /** @description Current probability that triggered the spike (0.0–1.0) */ + current_probability: number; + /** + * @description `"up"` = probability rising, `"down"` = probability falling + * @enum {string} + */ + spike_direction: "up" | "down"; + /** @description Percentage move that triggered this notification. Positive = up, negative = down. */ + spike_pct: number; + }; + PriceSpikePayload: { + /** @description Outcome token ID */ + position_id: string; + /** @description Market condition ID */ + condition_id?: string | null; + /** @description Event slug */ + event_slug?: string | null; + /** @description Outcome name (e.g. "Yes", "No") */ + outcome?: string | null; + /** + * Format: int16 + * @description Outcome index + */ + outcome_index?: number | null; + /** @description Price at the start of the observation window (baseline snapshot, 0.0–1.0) */ + previous_price: number; + /** @description Current price that triggered the spike (0.0–1.0) */ + current_price: number; + /** + * @description `"up"` = price rising, `"down"` = price falling + * @enum {string} + */ + spike_direction: "up" | "down"; + /** @description Percentage move that triggered this notification. Positive = up, negative = down. */ + spike_pct: number; + }; + /** @description Payload delivered when a market's volume has spiked since the last snapshot */ + MarketVolumeSpikePayload: { + /** @description Market condition ID */ + condition_id: string; + /** @description Aggregation window (e.g. "1h", "24h") */ + timeframe: string; + /** @description Current volume at the time of the spike (USD) */ + current_volume_usd: number; + /** @description Volume at the snapshot baseline (USD) */ + snapshot_volume_usd: number; + /** @description New volume since the snapshot that triggered this notification (USD) */ + delta_volume_usd: number; + /** @description Volume growth as a percentage of the snapshot (e.g. 200.0 means volume tripled) */ + spike_pct: number; + /** + * Format: int64 + * @description Total transactions in this timeframe + */ + txns: number; + /** @description Total fees in USD for this timeframe */ + fees: number; + }; + /** @description Payload delivered when an event's aggregated volume has spiked since the last snapshot */ + EventVolumeSpikePayload: { + /** @description Event slug */ + event_slug: string; + /** @description Aggregation window (e.g. "1h", "24h") */ + timeframe: string; + /** @description Current aggregated event volume at time of the spike (USD) */ + current_volume_usd: number; + /** @description Volume at the snapshot baseline (USD) */ + snapshot_volume_usd: number; + /** @description New volume since the snapshot that triggered this notification (USD) */ + delta_volume_usd: number; + /** @description Volume growth as a percentage of the snapshot (e.g. 200.0 means volume tripled) */ + spike_pct: number; + /** Format: int64 */ + txns: number; + fees: number; + }; + /** @description Payload delivered when a position's volume has spiked since the last snapshot */ + PositionVolumeSpikePayload: { + /** @description ERC-1155 outcome token ID */ + position_id: string; + /** @description Parent market condition ID */ + condition_id: string; + /** @description Outcome name (e.g. "Yes", "No") */ + outcome?: string | null; + /** Format: int16 */ + outcome_index?: number | null; + /** @description Aggregation window (e.g. "1h", "24h") */ + timeframe: string; + /** @description Current position volume at the time of the spike (USD) */ + current_volume_usd: number; + /** @description Volume at the snapshot baseline (USD) */ + snapshot_volume_usd: number; + /** @description New volume since the snapshot that triggered this notification (USD) */ + delta_volume_usd: number; + /** @description Volume growth as a percentage of the snapshot (e.g. 200.0 means volume tripled) */ + spike_pct: number; + /** Format: int64 */ + txns: number; + fees: number; + }; + /** @description Payload delivered when a trade occurs at a near-certain-outcome price */ + CloseToBondPayload: { + /** @description Limit-order maker wallet address (lowercase) */ + trader: string; + /** @description Order filler wallet address (lowercase) */ + taker: string; + /** @description ERC-1155 outcome token ID */ + position_id: string; + /** @description Parent market condition ID */ + condition_id?: string | null; + /** @description Outcome name (e.g. "Yes", "No") */ + outcome?: string | null; + /** @description 0 = Yes/Up, 1 = No */ + outcome_index?: number | null; + question?: string | null; + market_slug?: string | null; + event_slug?: string | null; + trade_id: string; + /** @description Transaction hash */ + hash: string; + /** Format: int64 */ + block: number; + /** + * Format: int64 + * @description Unix seconds + */ + confirmed_at: number; + /** @description USD size of the trade */ + amount_usd: number; + shares_amount: number; + /** @description Fee paid in USD */ + fee: number; + /** @enum {string} */ + side: "Buy" | "Sell"; + /** @description Price that triggered the notification (0.0–1.0) */ + price: number; + /** @description Implied probability (0.0–1.0) */ + probability?: number | null; + /** + * @description "high" when near YES (price ≥ threshold), "low" when near NO (price ≤ threshold) + * @enum {string} + */ + bond_side: "high" | "low"; + /** @description The probability threshold from the subscription filter that was breached */ + threshold: number; + }; + /** @description An outcome entry within a newly created market */ + MarketCreatedOutcome: { + /** @description Outcome index (0 = Yes, 1 = No) */ + index: number; + /** @description Outcome name (e.g. "Yes", "No") */ + name: string; + /** @description ERC-1155 position token ID for this outcome */ + position_id: string; + }; + /** @description Payload delivered when a new prediction market is detected on-chain and enriched with Gamma API metadata */ + MarketCreatedPayload: { + /** @description Condition ID (0x-prefixed hex, lowercase) */ + condition_id: string; + /** @description Market slug */ + market_slug: string; + /** @description Parent event slug */ + event_slug?: string | null; + /** @description Parent event ID */ + event_id?: string | null; + /** @description Parent event title */ + event_title?: string | null; + /** @description Series slug (for recurring markets) */ + series_slug?: string | null; + /** @description List of market outcomes with their position IDs */ + outcomes: components["schemas"]["MarketCreatedOutcome"][]; + /** @description Full market question text */ + question: string; + /** @description Short display title */ + title?: string | null; + /** @description Market description */ + description: string; + /** @description Market category (e.g. "Sports", "Politics") */ + category?: string | null; + /** @description Market tags */ + tags: string[]; + /** @description Cover image URL */ + image_url?: string | null; + /** @description Whether this is a neg-risk market */ + neg_risk: boolean; + }; + /** @description Payload delivered on every raw Chainlink price tick for a tracked crypto asset */ + AssetPriceTickPayload: { + /** + * @description Asset symbol + * @enum {string} + */ + symbol: "BTC" | "ETH" | "SOL" | "XRP" | "DOGE" | "BNB" | "HYPE"; + /** @description Current asset price in USD from the Chainlink feed */ + price: number; + /** + * Format: int64 + * @description Tick timestamp (milliseconds since Unix epoch) + */ + timestamp_ms: number; + }; + /** @description Payload delivered twice per candle — once on open and once on close. `close_price` is 0.0 on the "open" update. */ + AssetPriceWindowUpdatePayload: { + /** + * @description Asset symbol + * @enum {string} + */ + symbol: "BTC" | "ETH" | "SOL" | "XRP" | "DOGE" | "BNB" | "HYPE"; + /** + * @description Candle / window size + * @enum {string} + */ + variant: "5m" | "15m" | "1h" | "4h" | "1d" | "24h"; + /** + * Format: int64 + * @description Window start timestamp (milliseconds since Unix epoch) + */ + start_time: number; + /** + * Format: int64 + * @description Window end timestamp (milliseconds since Unix epoch) + */ + end_time: number; + /** @description Opening price at start_time (USD) */ + open_price: number; + /** @description Closing price at end_time (USD). 0.0 when update_type is "open" (not yet available). */ + close_price: number; + /** + * @description "open" when the candle opens, "close" when it closes with a confirmed price + * @enum {string} + */ + update_type: "open" | "close"; + }; + /** @description Subscription filters for the `trader_first_trade` event. All fields are optional. */ + TraderFirstTradeFilters: { + /** @description Only fire for trades by these wallet addresses (lowercase). Empty = all traders. */ + wallet_addresses?: string[]; + /** @description Restrict to trades in these markets. Empty = all markets. */ + condition_ids?: string[]; + /** @description Restrict to trades in markets belonging to these events. */ + event_slugs?: string[]; + /** @description Minimum trade size in USD. Omit to match all sizes. */ + min_usd_value?: number; + /** @description Only fire when the outcome probability is ≥ this value. */ + min_probability?: number; + /** @description Only fire when the outcome probability is ≤ this value. */ + max_probability?: number; + /** @description When `true`, suppress webhooks for short-term "updown" markets (event slugs containing `updown`). Default: `false`. */ + exclude_shortterm_markets?: boolean; + }; + /** @description Subscription filters for the `trader_new_market` event. All fields are optional. */ + TraderNewMarketFilters: { + /** @description Only fire for these wallet addresses (lowercase). Empty = all traders. */ + wallet_addresses?: string[]; + /** @description Restrict to these markets. */ + condition_ids?: string[]; + /** @description Restrict to markets belonging to these events. */ + event_slugs?: string[]; + /** @description When `true`, suppress webhooks for short-term "updown" markets. Default: `false`. */ + exclude_shortterm_markets?: boolean; + }; + /** @description Subscription filters for the `trader_whale_trade` event. All fields are optional. */ + TraderWhaleTradeFilters: { + /** @description Only fire for trades by these wallet addresses. Empty = all traders. */ + wallet_addresses?: string[]; + /** @description Restrict to these markets. */ + condition_ids?: string[]; + /** @description Restrict to markets belonging to these events. */ + event_slugs?: string[]; + /** @description Minimum trade size in USD. Defaults to 0 (matches all trades). */ + min_usd_value?: number; + /** @description Only fire when outcome probability is ≥ this value. */ + min_probability?: number; + /** @description Only fire when outcome probability is ≤ this value. */ + max_probability?: number; + /** @description When `true`, suppress webhooks for short-term "updown" markets. Default: `false`. */ + exclude_shortterm_markets?: boolean; + }; + /** @description Subscription filters for the `trader_new_trade` event. All fields are optional. */ + TraderNewTradeFilters: { + /** @description Only fire for trades by these wallet addresses. Empty = all traders. */ + wallet_addresses?: string[]; + /** @description Restrict to these markets. */ + condition_ids?: string[]; + /** @description Restrict to markets belonging to these events. */ + event_slugs?: string[]; + /** @description Minimum trade size in USD. Defaults to 0 (matches all trades). */ + min_usd_value?: number; + /** @description Only fire when outcome probability is ≥ this value. */ + min_probability?: number; + /** @description Only fire when outcome probability is ≤ this value. */ + max_probability?: number; + /** @description When `true`, suppress webhooks for short-term "updown" markets. Default: `false`. */ + exclude_shortterm_markets?: boolean; + }; + /** @description Subscription filters for the `trader_global_pnl` event. All fields are optional. */ + TraderGlobalPnlFilters: { + /** @description Track only these trader wallet addresses. Empty = all traders. */ + traders?: string[]; + /** @description Only fire when realized PnL ≥ this value (USD). Use negative values for loss thresholds. */ + min_realized_pnl_usd?: number; + /** @description Only fire when realized PnL ≤ this value (USD). */ + max_realized_pnl_usd?: number; + /** @description Only fire when total trading volume ≥ this value (USD). */ + min_volume_usd?: number; + /** @description Only fire when total trading volume ≤ this value (USD). */ + max_volume_usd?: number; + /** @description Only fire when buy volume ≥ this value (USD). */ + min_buy_usd?: number; + /** @description Only fire when sell volume ≥ this value (USD). */ + min_sell_volume_usd?: number; + /** @description Only fire when market win rate ≥ this percentage (0.0–100.0). */ + min_win_rate?: number; + /** + * Format: int64 + * @description Only fire when the trader has traded in ≥ this many markets. + */ + min_markets_traded?: number; + /** @description Restrict to these PnL windows. Empty = all windows. */ + timeframes?: ("1d" | "7d" | "30d" | "lifetime")[]; + }; + /** @description Subscription filters for the `trader_market_pnl` event. All fields are optional. */ + TraderMarketPnlFilters: { + /** @description Track only these trader wallet addresses. */ + traders?: string[]; + /** @description Restrict to these markets. */ + condition_ids?: string[]; + /** @description Restrict to markets in these events. */ + event_slugs?: string[]; + /** @description Only fire when per-market realized PnL ≥ this value (USD). */ + min_realized_pnl_usd?: number; + /** @description Only fire when per-market realized PnL ≤ this value (USD). */ + max_realized_pnl_usd?: number; + /** @description Only fire when total volume (buy + sell + redemption + merge) ≥ this value (USD). */ + min_volume_usd?: number; + /** @description Only fire when total volume ≤ this value (USD). */ + max_volume_usd?: number; + /** @description Only fire when buy volume in the market ≥ this value (USD). */ + min_buy_usd?: number; + /** @description Only fire when sell volume in the market ≥ this value (USD). */ + min_sell_volume_usd?: number; + /** @description Restrict to these PnL windows. */ + timeframes?: ("1d" | "7d" | "30d" | "lifetime")[]; + /** @description When `true`, suppress webhooks for short-term "updown" markets. Default: `false`. */ + exclude_shortterm_markets?: boolean; + }; + /** @description Subscription filters for the `trader_event_pnl` event. All fields are optional. */ + TraderEventPnlFilters: { + /** @description Track only these trader wallet addresses. */ + traders?: string[]; + /** @description Restrict to these events. */ + event_slugs?: string[]; + /** @description Only fire when per-event realized PnL ≥ this value (USD). */ + min_realized_pnl_usd?: number; + /** @description Only fire when per-event realized PnL ≤ this value (USD). */ + max_realized_pnl_usd?: number; + /** @description Only fire when total event volume ≥ this value (USD). */ + min_volume_usd?: number; + /** @description Only fire when total event volume ≤ this value (USD). */ + max_volume_usd?: number; + /** @description Only fire when buy volume within the event ≥ this value (USD). */ + min_buy_usd?: number; + /** @description Only fire when sell volume within the event ≥ this value (USD). */ + min_sell_volume_usd?: number; + /** + * Format: int64 + * @description Only fire when the trader has traded in ≥ this many markets within the event. + */ + min_markets_traded?: number; + /** @description Restrict to these PnL windows. */ + timeframes?: ("1d" | "7d" | "30d" | "lifetime")[]; + /** @description When `true`, suppress webhooks for short-term "updown" markets. Default: `false`. */ + exclude_shortterm_markets?: boolean; + }; + /** @description Subscription filters for the `condition_metrics` event. All fields are optional. */ + MarketMetricsFilters: { + /** @description Restrict to these markets. Empty = all markets. */ + condition_ids?: string[]; + /** @description Restrict to markets in these events. */ + event_slugs?: string[]; + /** @description Restrict to these aggregation windows. Empty = all windows. */ + timeframes?: ("1m" | "5m" | "30m" | "1h" | "6h" | "24h" | "7d" | "30d")[]; + /** @description Only fire when volume ≥ this value (USD). */ + min_volume_usd?: number; + /** @description Only fire when volume ≤ this value (USD). */ + max_volume_usd?: number; + /** + * Format: int64 + * @description Only fire when transaction count ≥ this value. + */ + min_txns?: number; + /** + * Format: int64 + * @description Only fire when unique trader count ≥ this value. + */ + min_unique_traders?: number; + /** @description Only fire when total fees ≥ this value (USD). */ + min_fees?: number; + }; + /** @description Subscription filters for the `event_metrics` event. All fields are optional. */ + EventMetricsFilters: { + /** @description Restrict to these events. Empty = all events. */ + event_slugs?: string[]; + /** @description Restrict to these aggregation windows. */ + timeframes?: ("1m" | "5m" | "30m" | "1h" | "6h" | "24h" | "7d" | "30d")[]; + /** @description Only fire when aggregated event volume ≥ this value (USD). */ + min_volume_usd?: number; + max_volume_usd?: number; + /** Format: int64 */ + min_txns?: number; + /** Format: int64 */ + min_unique_traders?: number; + min_fees?: number; + /** @description When `true`, suppress webhooks for short-term "updown" markets. Default: `false`. */ + exclude_shortterm_markets?: boolean; + }; + /** @description Subscription filters for the `position_metrics` event. All fields are optional. */ + PositionMetricsFilters: { + /** @description Restrict to these outcome token IDs. */ + position_ids?: string[]; + /** @description Restrict to positions within these markets. */ + condition_ids?: string[]; + /** @description Restrict to positions with these outcome names (e.g. ["Yes", "No"]). */ + outcomes?: string[]; + /** @description Restrict to these aggregation windows. */ + timeframes?: ("1m" | "5m" | "30m" | "1h" | "6h" | "24h" | "7d" | "30d")[]; + /** @description Only fire when position volume ≥ this value (USD). */ + min_volume_usd?: number; + max_volume_usd?: number; + min_buy_usd?: number; + min_sell_volume_usd?: number; + /** Format: int64 */ + min_txns?: number; + /** Format: int64 */ + min_unique_traders?: number; + /** @description Only fire when price change % ≥ this value. */ + min_price_change_pct?: number; + /** @description Only fire when probability change % ≥ this value. */ + min_probability_change_pct?: number; + min_fees?: number; + }; + /** @description Subscription filters for the `market_volume_milestone` event. */ + MarketVolumeMilestoneFilters: { + /** @description **Required.** Aggregation windows to monitor (e.g. ["1h", "24h"]). */ + timeframes: ("1m" | "5m" | "30m" | "1h" | "6h" | "24h" | "7d" | "30d")[]; + /** @description Restrict to these markets. Empty = all markets. */ + condition_ids?: string[]; + /** @description Specific USD milestones to trigger on (e.g. [10000, 100000, 1000000]). Empty = all milestones. */ + milestone_amounts?: number[]; + }; + /** @description Subscription filters for the `event_volume_milestone` event. */ + EventVolumeMilestoneFilters: { + /** @description **Required.** Aggregation windows to monitor. */ + timeframes: ("1m" | "5m" | "30m" | "1h" | "6h" | "24h" | "7d" | "30d")[]; + /** @description Restrict to these events. */ + event_slugs?: string[]; + /** @description Specific USD milestones to trigger on. */ + milestone_amounts?: number[]; + /** @description When `true`, suppress webhooks for short-term "updown" markets. Default: `false`. */ + exclude_shortterm_markets?: boolean; + }; + /** @description Subscription filters for the `position_volume_milestone` event. */ + PositionVolumeMilestoneFilters: { + /** @description **Required.** Aggregation windows to monitor. */ + timeframes: ("1m" | "5m" | "30m" | "1h" | "6h" | "24h" | "7d" | "30d")[]; + /** @description Restrict to these outcome token IDs. */ + position_ids?: string[]; + /** @description Restrict to positions within these markets. */ + condition_ids?: string[]; + /** @description Specific USD milestones to trigger on. */ + milestone_amounts?: number[]; + }; + /** @description Subscription filters for the `probability_spike` event. */ + ProbabilitySpikeFilters: { + /** @description Restrict to specific outcome token IDs. Empty = all positions. */ + position_ids?: string[]; + /** @description Restrict to specific market condition IDs. Empty = all markets. */ + condition_ids?: string[]; + /** @description Restrict to specific events. Empty = all events. */ + event_slugs?: string[]; + /** @description Restrict to these outcome names (e.g. ["Yes", "No"]). */ + outcomes?: string[]; + /** @description Minimum probability percentage move to trigger (e.g. `10` for a 10% move). */ + min_probability_change_pct?: number; + /** + * @description `"up"` = probability rising only (default when omitted), `"down"` = falling only, `"both"` = either direction. + * @enum {string} + */ + spike_direction?: "up" | "down" | "both"; + /** @description Observation window in seconds. The first trade in each window sets the reference price; subsequent trades are compared to it. E.g. `60` detects moves that occur within 60 seconds. */ + window_secs?: number; + /** @description When `true`, suppress webhooks for short-term "updown" markets. Default: `false`. */ + exclude_shortterm_markets?: boolean; + }; + /** @description Subscription filters for the `price_spike` event. */ + PriceSpikeFilters: { + /** @description Restrict to specific outcome token IDs. Empty = all positions. */ + position_ids?: string[]; + /** @description Restrict to specific market condition IDs. Empty = all markets. */ + condition_ids?: string[]; + /** @description Restrict to specific events. Empty = all events. */ + event_slugs?: string[]; + /** @description Restrict to these outcome names (e.g. ["Yes", "No"]). */ + outcomes?: string[]; + /** @description Minimum price percentage move to trigger (e.g. `10` for a 10% move). */ + min_price_change_pct?: number; + /** + * @description `"up"` = price rising only (default when omitted), `"down"` = falling only, `"both"` = either direction. + * @enum {string} + */ + spike_direction?: "up" | "down" | "both"; + /** @description Observation window in seconds. The first trade in each window sets the reference price; subsequent trades are compared to it. E.g. `60` detects moves that occur within 60 seconds. */ + window_secs?: number; + /** @description When `true`, suppress webhooks for short-term "updown" markets. Default: `false`. */ + exclude_shortterm_markets?: boolean; + }; + /** @description Subscription filters for the `market_volume_spike` event. `spike_ratio` is required. */ + MarketVolumeSpikeFilters: { + /** @description **Required.** Multiplier threshold (must be > 1.0). Fires when current volume >= snapshot × ratio. The snapshot is set automatically on first data and resets after each fire. */ + spike_ratio: number; + /** @description Force snapshot reset after this many seconds (max 600 / 10 minutes). */ + window_secs?: number; + /** @description Restrict to these markets. Empty = all markets. */ + condition_ids?: string[]; + /** @description Restrict to these aggregation windows. Empty = all windows. */ + timeframes?: ("1m" | "5m" | "30m" | "1h" | "6h" | "1d" | "24h" | "7d" | "30d")[]; + }; + /** @description Subscription filters for the `event_volume_spike` event. `spike_ratio` is required. */ + EventVolumeSpikeFilters: { + /** @description **Required.** Multiplier threshold (must be > 1.0). Fires when current volume >= snapshot × ratio. */ + spike_ratio: number; + /** @description Force snapshot reset after this many seconds (max 600 / 10 minutes). */ + window_secs?: number; + /** @description Restrict to these events. */ + event_slugs?: string[]; + /** @description Restrict to these aggregation windows. */ + timeframes?: ("1m" | "5m" | "30m" | "1h" | "6h" | "1d" | "24h" | "7d" | "30d")[]; + /** @description When `true`, suppress webhooks for short-term "updown" markets. Default: `false`. */ + exclude_shortterm_markets?: boolean; + }; + /** + * @description All alert event types supported by both HTTP webhooks and the alerts WebSocket. + * @enum {string} + */ + WsAlertEventType: "trader_first_trade" | "trader_new_market" | "trader_whale_trade" | "trader_new_trade" | "trader_global_pnl" | "trader_market_pnl" | "trader_event_pnl" | "condition_metrics" | "event_metrics" | "position_metrics" | "market_volume_milestone" | "event_volume_milestone" | "position_volume_milestone" | "probability_spike" | "price_spike" | "market_volume_spike" | "event_volume_spike" | "position_volume_spike" | "close_to_bond" | "market_created" | "asset_price_tick" | "asset_price_window_update"; + /** @description Server acknowledgement for a successful alert subscription. */ + WsAlertSubscribedResponse: { + /** @enum {string} */ + op: "subscribed"; + event: components["schemas"]["WsAlertEventType"]; + /** Format: uuid */ + subscription_id: string; + }; + /** @description Server acknowledgement for a successful alert unsubscription. */ + WsAlertUnsubscribedResponse: { + /** @enum {string} */ + op: "unsubscribed"; + event: components["schemas"]["WsAlertEventType"]; + }; + /** @description Error returned by the alerts WebSocket when a message is invalid or a subscription request fails. */ + WsAlertErrorResponse: { + error: string; + }; + WsAlertTraderFirstTradeSubscribeMessage: { + /** @enum {string} */ + op: "subscribe"; + /** @enum {string} */ + event: "trader_first_trade"; + } & components["schemas"]["TraderFirstTradeFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "trader_first_trade"; + }; + WsAlertTraderFirstTradeUnsubscribeMessage: { + /** @enum {string} */ + op: "unsubscribe"; + /** @enum {string} */ + event: "trader_first_trade"; + } & components["schemas"]["TraderFirstTradeFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "trader_first_trade"; + }; + /** + * @description Pushed `trader_first_trade` alert. The `data` payload matches the corresponding HTTP webhook payload schema. + * @example { + * "event": "trader_first_trade", + * "timestamp": 1743500000000, + * "data": { + * "trader": "0x0000000000000000000000000000000000000000", + * "taker": "0x0000000000000000000000000000000000000000", + * "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", + * "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + * "outcome": "Yes", + * "outcome_index": 0, + * "question": "Will this test webhook fire correctly?", + * "market_slug": "test-market-0000000000", + * "event_slug": "test-event-0000000000", + * "trade_id": "00000000-0000-0000-0000-000000000000", + * "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + * "block": 0, + * "confirmed_at": 1700000000, + * "amount_usd": 125, + * "shares_amount": 250, + * "fee": 0.125, + * "side": "Buy", + * "price": 0.5, + * "exchange": "polymarket", + * "trade_type": "OrderFilled" + * } + * } + */ + WsAlertTraderFirstTradeEvent: { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "trader_first_trade"; + /** + * Format: int64 + * @description Unix timestamp in milliseconds + */ + timestamp: number; + data: components["schemas"]["FirstTradePayload"]; + }; + WsAlertTraderNewMarketSubscribeMessage: { + /** @enum {string} */ + op: "subscribe"; + /** @enum {string} */ + event: "trader_new_market"; + } & components["schemas"]["TraderNewMarketFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "trader_new_market"; + }; + WsAlertTraderNewMarketUnsubscribeMessage: { + /** @enum {string} */ + op: "unsubscribe"; + /** @enum {string} */ + event: "trader_new_market"; + } & components["schemas"]["TraderNewMarketFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "trader_new_market"; + }; + /** + * @description Pushed `trader_new_market` alert. The `data` payload matches the corresponding HTTP webhook payload schema. + * @example { + * "event": "trader_new_market", + * "timestamp": 1743500000000, + * "data": { + * "trader": "0x0000000000000000000000000000000000000000", + * "taker": "0x0000000000000000000000000000000000000000", + * "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", + * "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + * "outcome": "Yes", + * "outcome_index": 0, + * "question": "Will this test webhook fire correctly?", + * "market_slug": "test-market-0000000000", + * "event_slug": "test-event-0000000000", + * "trade_id": "00000000-0000-0000-0000-000000000000", + * "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + * "block": 0, + * "confirmed_at": 1700000000, + * "amount_usd": 125, + * "shares_amount": 250, + * "fee": 0.125, + * "side": "Buy", + * "price": 0.5, + * "probability": 0.5, + * "exchange": "polymarket", + * "trade_type": "OrderFilled" + * } + * } + */ + WsAlertTraderNewMarketEvent: { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "trader_new_market"; + /** + * Format: int64 + * @description Unix timestamp in milliseconds + */ + timestamp: number; + data: components["schemas"]["NewMarketPayload"]; + }; + WsAlertTraderWhaleTradeSubscribeMessage: { + /** @enum {string} */ + op: "subscribe"; + /** @enum {string} */ + event: "trader_whale_trade"; + } & components["schemas"]["TraderWhaleTradeFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "trader_whale_trade"; + }; + WsAlertTraderWhaleTradeUnsubscribeMessage: { + /** @enum {string} */ + op: "unsubscribe"; + /** @enum {string} */ + event: "trader_whale_trade"; + } & components["schemas"]["TraderWhaleTradeFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "trader_whale_trade"; + }; + /** + * @description Pushed `trader_whale_trade` alert. The `data` payload matches the corresponding HTTP webhook payload schema. + * @example { + * "event": "trader_whale_trade", + * "timestamp": 1743500000000, + * "data": { + * "trader": "0x0000000000000000000000000000000000000000", + * "taker": "0x0000000000000000000000000000000000000000", + * "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", + * "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + * "outcome": "Yes", + * "outcome_index": 0, + * "question": "Will this test webhook fire correctly?", + * "market_slug": "test-market-0000000000", + * "event_slug": "test-event-0000000000", + * "trade_id": "00000000-0000-0000-0000-000000000000", + * "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + * "block": 0, + * "confirmed_at": 1700000000, + * "amount_usd": 125, + * "shares_amount": 250, + * "fee": 0.125, + * "side": "Buy", + * "price": 0.5, + * "probability": 0.5, + * "exchange": "polymarket", + * "trade_type": "OrderFilled" + * } + * } + */ + WsAlertTraderWhaleTradeEvent: { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "trader_whale_trade"; + /** + * Format: int64 + * @description Unix timestamp in milliseconds + */ + timestamp: number; + data: components["schemas"]["WhaleTradePayload"]; + }; + WsAlertTraderNewTradeSubscribeMessage: { + /** @enum {string} */ + op: "subscribe"; + /** @enum {string} */ + event: "trader_new_trade"; + } & components["schemas"]["TraderNewTradeFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "trader_new_trade"; + }; + WsAlertTraderNewTradeUnsubscribeMessage: { + /** @enum {string} */ + op: "unsubscribe"; + /** @enum {string} */ + event: "trader_new_trade"; + } & components["schemas"]["TraderNewTradeFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "trader_new_trade"; + }; + /** + * @description Pushed `trader_new_trade` alert. The `data` payload matches the corresponding HTTP webhook payload schema. + * @example { + * "event": "trader_new_trade", + * "timestamp": 1743500000000, + * "data": { + * "trader": "0x0000000000000000000000000000000000000000", + * "taker": "0x0000000000000000000000000000000000000000", + * "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", + * "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + * "outcome": "Yes", + * "outcome_index": 0, + * "question": "Will this test webhook fire correctly?", + * "market_slug": "test-market-0000000000", + * "event_slug": "test-event-0000000000", + * "trade_id": "00000000-0000-0000-0000-000000000000", + * "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + * "block": 0, + * "confirmed_at": 1700000000, + * "amount_usd": 25, + * "shares_amount": 50, + * "fee": 0.025, + * "side": "Buy", + * "price": 0.5, + * "probability": 0.5, + * "exchange": "polymarket", + * "trade_type": "OrderFilled" + * } + * } + */ + WsAlertTraderNewTradeEvent: { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "trader_new_trade"; + /** + * Format: int64 + * @description Unix timestamp in milliseconds + */ + timestamp: number; + data: components["schemas"]["NewTradePayload"]; + }; + WsAlertTraderGlobalPnlSubscribeMessage: { + /** @enum {string} */ + op: "subscribe"; + /** @enum {string} */ + event: "trader_global_pnl"; + } & components["schemas"]["TraderGlobalPnlFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "trader_global_pnl"; + }; + WsAlertTraderGlobalPnlUnsubscribeMessage: { + /** @enum {string} */ + op: "unsubscribe"; + /** @enum {string} */ + event: "trader_global_pnl"; + } & components["schemas"]["TraderGlobalPnlFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "trader_global_pnl"; + }; + /** + * @description Pushed `trader_global_pnl` alert. The `data` payload matches the corresponding HTTP webhook payload schema. + * @example { + * "event": "trader_global_pnl", + * "timestamp": 1743500000000, + * "data": { + * "trader": "0x0000000000000000000000000000000000000000", + * "timeframe": "7d", + * "realized_pnl_usd": 250, + * "events_traded": 3, + * "markets_traded": 5, + * "total_buys": 12, + * "total_sells": 8, + * "total_redemptions": 1, + * "total_merges": 0, + * "total_volume_usd": 1500, + * "buy_volume_usd": 900, + * "sell_volume_usd": 600, + * "redemption_volume_usd": 50, + * "merge_volume_usd": 0, + * "markets_won": 3, + * "markets_lost": 2, + * "market_win_rate_pct": 60, + * "avg_pnl_per_market": 50, + * "avg_pnl_per_trade": 12.5, + * "avg_hold_time_seconds": 86400, + * "total_fees": 7.5, + * "best_trade_pnl_usd": 180, + * "best_trade_condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + * "first_trade_at": 1700000000, + * "last_trade_at": 1700000000 + * } + * } + */ + WsAlertTraderGlobalPnlEvent: { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "trader_global_pnl"; + /** + * Format: int64 + * @description Unix timestamp in milliseconds + */ + timestamp: number; + data: components["schemas"]["GlobalPnlPayload"]; + }; + WsAlertTraderMarketPnlSubscribeMessage: { + /** @enum {string} */ + op: "subscribe"; + /** @enum {string} */ + event: "trader_market_pnl"; + } & components["schemas"]["TraderMarketPnlFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "trader_market_pnl"; + }; + WsAlertTraderMarketPnlUnsubscribeMessage: { + /** @enum {string} */ + op: "unsubscribe"; + /** @enum {string} */ + event: "trader_market_pnl"; + } & components["schemas"]["TraderMarketPnlFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "trader_market_pnl"; + }; + /** + * @description Pushed `trader_market_pnl` alert. The `data` payload matches the corresponding HTTP webhook payload schema. + * @example { + * "event": "trader_market_pnl", + * "timestamp": 1743500000000, + * "data": { + * "trader": "0x0000000000000000000000000000000000000000", + * "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + * "event_slug": "test-event-0000000000", + * "timeframe": "7d", + * "outcomes_traded": 2, + * "total_buys": 4, + * "total_sells": 3, + * "total_redemptions": 1, + * "total_merges": 0, + * "buy_usd": 300, + * "sell_usd": 200, + * "redemption_usd": 50, + * "merge_usd": 0, + * "realized_pnl_usd": 100, + * "winning_outcomes": 1, + * "total_fees": 2.5, + * "first_trade_at": 1700000000, + * "last_trade_at": 1700000000 + * } + * } + */ + WsAlertTraderMarketPnlEvent: { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "trader_market_pnl"; + /** + * Format: int64 + * @description Unix timestamp in milliseconds + */ + timestamp: number; + data: components["schemas"]["MarketPnlPayload"]; + }; + WsAlertTraderEventPnlSubscribeMessage: { + /** @enum {string} */ + op: "subscribe"; + /** @enum {string} */ + event: "trader_event_pnl"; + } & components["schemas"]["TraderEventPnlFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "trader_event_pnl"; + }; + WsAlertTraderEventPnlUnsubscribeMessage: { + /** @enum {string} */ + op: "unsubscribe"; + /** @enum {string} */ + event: "trader_event_pnl"; + } & components["schemas"]["TraderEventPnlFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "trader_event_pnl"; + }; + /** + * @description Pushed `trader_event_pnl` alert. The `data` payload matches the corresponding HTTP webhook payload schema. + * @example { + * "event": "trader_event_pnl", + * "timestamp": 1743500000000, + * "data": { + * "trader": "0x0000000000000000000000000000000000000000", + * "event_slug": "test-event-0000000000", + * "timeframe": "7d", + * "markets_traded": 2, + * "outcomes_traded": 3, + * "total_buys": 6, + * "total_sells": 4, + * "total_redemptions": 1, + * "total_merges": 0, + * "total_volume_usd": 800, + * "buy_usd": 480, + * "sell_usd": 320, + * "redemption_usd": 50, + * "merge_usd": 0, + * "realized_pnl_usd": 150, + * "winning_markets": 1, + * "losing_markets": 1, + * "total_fees": 4, + * "first_trade_at": 1700000000, + * "last_trade_at": 1700000000 + * } + * } + */ + WsAlertTraderEventPnlEvent: { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "trader_event_pnl"; + /** + * Format: int64 + * @description Unix timestamp in milliseconds + */ + timestamp: number; + data: components["schemas"]["EventPnlPayload"]; + }; + WsAlertConditionMetricsSubscribeMessage: { + /** @enum {string} */ + op: "subscribe"; + /** @enum {string} */ + event: "condition_metrics"; + } & components["schemas"]["MarketMetricsFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "condition_metrics"; + }; + WsAlertConditionMetricsUnsubscribeMessage: { + /** @enum {string} */ + op: "unsubscribe"; + /** @enum {string} */ + event: "condition_metrics"; + } & components["schemas"]["MarketMetricsFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "condition_metrics"; + }; + /** + * @description Pushed `condition_metrics` alert. The `data` payload matches the corresponding HTTP webhook payload schema. + * @example { + * "event": "condition_metrics", + * "timestamp": 1743500000000, + * "data": { + * "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + * "timeframe": "1h", + * "volume_usd": 50000, + * "fees": 250, + * "txns": 320, + * "unique_traders": 85 + * } + * } + */ + WsAlertConditionMetricsEvent: { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "condition_metrics"; + /** + * Format: int64 + * @description Unix timestamp in milliseconds + */ + timestamp: number; + data: components["schemas"]["ConditionMetricsPayload"]; + }; + WsAlertEventMetricsSubscribeMessage: { + /** @enum {string} */ + op: "subscribe"; + /** @enum {string} */ + event: "event_metrics"; + } & components["schemas"]["EventMetricsFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "event_metrics"; + }; + WsAlertEventMetricsUnsubscribeMessage: { + /** @enum {string} */ + op: "unsubscribe"; + /** @enum {string} */ + event: "event_metrics"; + } & components["schemas"]["EventMetricsFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "event_metrics"; + }; + /** + * @description Pushed `event_metrics` alert. The `data` payload matches the corresponding HTTP webhook payload schema. + * @example { + * "event": "event_metrics", + * "timestamp": 1743500000000, + * "data": { + * "event_slug": "test-event-0000000000", + * "timeframe": "1h", + * "volume_usd": 120000, + * "fees": 600, + * "txns": 740, + * "unique_traders": 210 + * } + * } + */ + WsAlertEventMetricsEvent: { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "event_metrics"; + /** + * Format: int64 + * @description Unix timestamp in milliseconds + */ + timestamp: number; + data: components["schemas"]["EventMetricsPayload"]; + }; + WsAlertPositionMetricsSubscribeMessage: { + /** @enum {string} */ + op: "subscribe"; + /** @enum {string} */ + event: "position_metrics"; + } & components["schemas"]["PositionMetricsFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "position_metrics"; + }; + WsAlertPositionMetricsUnsubscribeMessage: { + /** @enum {string} */ + op: "unsubscribe"; + /** @enum {string} */ + event: "position_metrics"; + } & components["schemas"]["PositionMetricsFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "position_metrics"; + }; + /** + * @description Pushed `position_metrics` alert. The `data` payload matches the corresponding HTTP webhook payload schema. + * @example { + * "event": "position_metrics", + * "timestamp": 1743500000000, + * "data": { + * "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", + * "outcome": "Yes", + * "outcome_index": 0, + * "timeframe": "1h", + * "volume_usd": 25000, + * "buy_volume_usd": 15000, + * "sell_volume_usd": 10000, + * "fees": 125, + * "txns": 160, + * "buys": 95, + * "sells": 65, + * "unique_traders": 48, + * "price_open": 0.48, + * "price_close": 0.52, + * "price_high": 0.55, + * "price_low": 0.46, + * "probability_open": 0.48, + * "probability_close": 0.52, + * "probability_high": 0.55, + * "probability_low": 0.46 + * } + * } + */ + WsAlertPositionMetricsEvent: { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "position_metrics"; + /** + * Format: int64 + * @description Unix timestamp in milliseconds + */ + timestamp: number; + data: components["schemas"]["PositionMetricsPayload"]; + }; + WsAlertMarketVolumeMilestoneSubscribeMessage: { + /** @enum {string} */ + op: "subscribe"; + /** @enum {string} */ + event: "market_volume_milestone"; + } & components["schemas"]["MarketVolumeMilestoneFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "market_volume_milestone"; + }; + WsAlertMarketVolumeMilestoneUnsubscribeMessage: { + /** @enum {string} */ + op: "unsubscribe"; + /** @enum {string} */ + event: "market_volume_milestone"; + } & components["schemas"]["MarketVolumeMilestoneFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "market_volume_milestone"; + }; + /** + * @description Pushed `market_volume_milestone` alert. The `data` payload matches the corresponding HTTP webhook payload schema. + * @example { + * "event": "market_volume_milestone", + * "timestamp": 1743500000000, + * "data": { + * "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + * "timeframe": "24h", + * "milestone_usd": 100000, + * "current_volume_usd": 100125, + * "fees": 500, + * "txns": 650 + * } + * } + */ + WsAlertMarketVolumeMilestoneEvent: { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "market_volume_milestone"; + /** + * Format: int64 + * @description Unix timestamp in milliseconds + */ + timestamp: number; + data: components["schemas"]["VolumeMilestonePayload"]; + }; + WsAlertEventVolumeMilestoneSubscribeMessage: { + /** @enum {string} */ + op: "subscribe"; + /** @enum {string} */ + event: "event_volume_milestone"; + } & components["schemas"]["EventVolumeMilestoneFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "event_volume_milestone"; + }; + WsAlertEventVolumeMilestoneUnsubscribeMessage: { + /** @enum {string} */ + op: "unsubscribe"; + /** @enum {string} */ + event: "event_volume_milestone"; + } & components["schemas"]["EventVolumeMilestoneFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "event_volume_milestone"; + }; + /** + * @description Pushed `event_volume_milestone` alert. The `data` payload matches the corresponding HTTP webhook payload schema. + * @example { + * "event": "event_volume_milestone", + * "timestamp": 1743500000000, + * "data": { + * "event_slug": "test-event-0000000000", + * "timeframe": "24h", + * "milestone_usd": 500000, + * "current_volume_usd": 500250, + * "fees": 2500, + * "txns": 3200 + * } + * } + */ + WsAlertEventVolumeMilestoneEvent: { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "event_volume_milestone"; + /** + * Format: int64 + * @description Unix timestamp in milliseconds + */ + timestamp: number; + data: components["schemas"]["EventVolumeMilestonePayload"]; + }; + WsAlertPositionVolumeMilestoneSubscribeMessage: { + /** @enum {string} */ + op: "subscribe"; + /** @enum {string} */ + event: "position_volume_milestone"; + } & components["schemas"]["PositionVolumeMilestoneFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "position_volume_milestone"; + }; + WsAlertPositionVolumeMilestoneUnsubscribeMessage: { + /** @enum {string} */ + op: "unsubscribe"; + /** @enum {string} */ + event: "position_volume_milestone"; + } & components["schemas"]["PositionVolumeMilestoneFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "position_volume_milestone"; + }; + /** + * @description Pushed `position_volume_milestone` alert. The `data` payload matches the corresponding HTTP webhook payload schema. + * @example { + * "event": "position_volume_milestone", + * "timestamp": 1743500000000, + * "data": { + * "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + * "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", + * "outcome": "Yes", + * "outcome_index": 0, + * "timeframe": "24h", + * "milestone_usd": 50000, + * "current_volume_usd": 50125, + * "buy_volume_usd": 30000, + * "sell_volume_usd": 20000, + * "fees": 250, + * "txns": 320, + * "buys": 190, + * "sells": 130 + * } + * } + */ + WsAlertPositionVolumeMilestoneEvent: { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "position_volume_milestone"; + /** + * Format: int64 + * @description Unix timestamp in milliseconds + */ + timestamp: number; + data: components["schemas"]["PositionVolumeMilestonePayload"]; + }; + WsAlertProbabilitySpikeSubscribeMessage: { + /** @enum {string} */ + op: "subscribe"; + /** @enum {string} */ + event: "probability_spike"; + } & components["schemas"]["ProbabilitySpikeFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "probability_spike"; + }; + WsAlertProbabilitySpikeUnsubscribeMessage: { + /** @enum {string} */ + op: "unsubscribe"; + /** @enum {string} */ + event: "probability_spike"; + } & components["schemas"]["ProbabilitySpikeFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "probability_spike"; + }; + /** + * @description Pushed `probability_spike` alert. The `data` payload matches the corresponding HTTP webhook payload schema. + * @example { + * "event": "probability_spike", + * "timestamp": 1743500000000, + * "data": { + * "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", + * "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + * "event_slug": "test-event-0000000000", + * "outcome": "Yes", + * "outcome_index": 0, + * "previous_probability": 0.4, + * "current_probability": 0.5, + * "spike_direction": "up", + * "spike_pct": 25 + * } + * } + */ + WsAlertProbabilitySpikeEvent: { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "probability_spike"; + /** + * Format: int64 + * @description Unix timestamp in milliseconds + */ + timestamp: number; + data: components["schemas"]["ProbabilitySpikePayload"]; + }; + WsAlertPriceSpikeSubscribeMessage: { + /** @enum {string} */ + op: "subscribe"; + /** @enum {string} */ + event: "price_spike"; + } & components["schemas"]["PriceSpikeFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "price_spike"; + }; + WsAlertPriceSpikeUnsubscribeMessage: { + /** @enum {string} */ + op: "unsubscribe"; + /** @enum {string} */ + event: "price_spike"; + } & components["schemas"]["PriceSpikeFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "price_spike"; + }; + /** + * @description Pushed `price_spike` alert. The `data` payload matches the corresponding HTTP webhook payload schema. + * @example { + * "event": "price_spike", + * "timestamp": 1743500000000, + * "data": { + * "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", + * "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + * "event_slug": "test-event-0000000000", + * "outcome": "Yes", + * "outcome_index": 0, + * "previous_price": 0.4, + * "current_price": 0.5, + * "spike_direction": "up", + * "spike_pct": 25 + * } + * } + */ + WsAlertPriceSpikeEvent: { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "price_spike"; + /** + * Format: int64 + * @description Unix timestamp in milliseconds + */ + timestamp: number; + data: components["schemas"]["PriceSpikePayload"]; + }; + WsAlertMarketVolumeSpikeSubscribeMessage: { + /** @enum {string} */ + op: "subscribe"; + /** @enum {string} */ + event: "market_volume_spike"; + } & components["schemas"]["MarketVolumeSpikeFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "market_volume_spike"; + }; + WsAlertMarketVolumeSpikeUnsubscribeMessage: { + /** @enum {string} */ + op: "unsubscribe"; + /** @enum {string} */ + event: "market_volume_spike"; + } & components["schemas"]["MarketVolumeSpikeFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "market_volume_spike"; + }; + /** + * @description Pushed `market_volume_spike` alert. The `data` payload matches the corresponding HTTP webhook payload schema. + * @example { + * "event": "market_volume_spike", + * "timestamp": 1743500000000, + * "data": { + * "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + * "timeframe": "1h", + * "current_volume_usd": 32000, + * "snapshot_volume_usd": 10000, + * "delta_volume_usd": 22000, + * "spike_pct": 220, + * "txns": 480, + * "fees": 160 + * } + * } + */ + WsAlertMarketVolumeSpikeEvent: { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "market_volume_spike"; + /** + * Format: int64 + * @description Unix timestamp in milliseconds + */ + timestamp: number; + data: components["schemas"]["MarketVolumeSpikePayload"]; + }; + WsAlertEventVolumeSpikeSubscribeMessage: { + /** @enum {string} */ + op: "subscribe"; + /** @enum {string} */ + event: "event_volume_spike"; + } & components["schemas"]["EventVolumeSpikeFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "event_volume_spike"; + }; + WsAlertEventVolumeSpikeUnsubscribeMessage: { + /** @enum {string} */ + op: "unsubscribe"; + /** @enum {string} */ + event: "event_volume_spike"; + } & components["schemas"]["EventVolumeSpikeFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "event_volume_spike"; + }; + /** + * @description Pushed `event_volume_spike` alert. The `data` payload matches the corresponding HTTP webhook payload schema. + * @example { + * "event": "event_volume_spike", + * "timestamp": 1743500000000, + * "data": { + * "event_slug": "test-event-0000000000", + * "timeframe": "1h", + * "current_volume_usd": 140000, + * "snapshot_volume_usd": 50000, + * "delta_volume_usd": 90000, + * "spike_pct": 180, + * "txns": 1100, + * "fees": 700 + * } + * } + */ + WsAlertEventVolumeSpikeEvent: { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "event_volume_spike"; + /** + * Format: int64 + * @description Unix timestamp in milliseconds + */ + timestamp: number; + data: components["schemas"]["EventVolumeSpikePayload"]; + }; + WsAlertPositionVolumeSpikeSubscribeMessage: { + /** @enum {string} */ + op: "subscribe"; + /** @enum {string} */ + event: "position_volume_spike"; + } & components["schemas"]["PositionVolumeSpikeFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "position_volume_spike"; + }; + WsAlertPositionVolumeSpikeUnsubscribeMessage: { + /** @enum {string} */ + op: "unsubscribe"; + /** @enum {string} */ + event: "position_volume_spike"; + } & components["schemas"]["PositionVolumeSpikeFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "position_volume_spike"; + }; + /** + * @description Pushed `position_volume_spike` alert. The `data` payload matches the corresponding HTTP webhook payload schema. + * @example { + * "event": "position_volume_spike", + * "timestamp": 1743500000000, + * "data": { + * "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", + * "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + * "outcome": "Yes", + * "outcome_index": 0, + * "timeframe": "1h", + * "current_volume_usd": 20500, + * "snapshot_volume_usd": 5000, + * "delta_volume_usd": 15500, + * "spike_pct": 310, + * "txns": 240, + * "fees": 102.5 + * } + * } + */ + WsAlertPositionVolumeSpikeEvent: { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "position_volume_spike"; + /** + * Format: int64 + * @description Unix timestamp in milliseconds + */ + timestamp: number; + data: components["schemas"]["PositionVolumeSpikePayload"]; + }; + WsAlertCloseToBondSubscribeMessage: ({ + /** @enum {string} */ + op: "subscribe"; + /** @enum {string} */ + event: "close_to_bond"; + } & components["schemas"]["CloseToBondFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "close_to_bond"; + }) | unknown | unknown; + WsAlertCloseToBondUnsubscribeMessage: ({ + /** @enum {string} */ + op: "unsubscribe"; + /** @enum {string} */ + event: "close_to_bond"; + } & components["schemas"]["CloseToBondFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "close_to_bond"; + }) | unknown | unknown; + /** + * @description Pushed `close_to_bond` alert. The `data` payload matches the corresponding HTTP webhook payload schema. + * @example { + * "event": "close_to_bond", + * "timestamp": 1743500000000, + * "data": { + * "trader": "0x0000000000000000000000000000000000000000", + * "taker": "0x0000000000000000000000000000000000000000", + * "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", + * "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + * "outcome": "Yes", + * "outcome_index": 0, + * "question": "Will this test webhook fire correctly?", + * "market_slug": "test-market-0000000000", + * "event_slug": "test-event-0000000000", + * "trade_id": "00000000-0000-0000-0000-000000000000", + * "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + * "block": 0, + * "confirmed_at": 1700000000, + * "amount_usd": 500, + * "shares_amount": 515.46, + * "fee": 2.5, + * "side": "Buy", + * "price": 0.97, + * "probability": 0.97, + * "bond_side": "high", + * "threshold": 0.95 + * } + * } + */ + WsAlertCloseToBondEvent: { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "close_to_bond"; + /** + * Format: int64 + * @description Unix timestamp in milliseconds + */ + timestamp: number; + data: components["schemas"]["CloseToBondPayload"]; + }; + WsAlertMarketCreatedSubscribeMessage: { + /** @enum {string} */ + op: "subscribe"; + /** @enum {string} */ + event: "market_created"; + } & components["schemas"]["MarketCreatedFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "market_created"; + }; + WsAlertMarketCreatedUnsubscribeMessage: { + /** @enum {string} */ + op: "unsubscribe"; + /** @enum {string} */ + event: "market_created"; + } & components["schemas"]["MarketCreatedFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "market_created"; + }; + /** + * @description Pushed `market_created` alert. The `data` payload matches the corresponding HTTP webhook payload schema. + * @example { + * "event": "market_created", + * "timestamp": 1743500000000, + * "data": { + * "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + * "market_slug": "test-market-0000000000", + * "event_slug": "test-event-0000000000", + * "event_id": null, + * "event_title": "Test Event 0000", + * "series_slug": null, + * "outcomes": [ + * { + * "index": 0, + * "name": "Yes", + * "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656" + * }, + * { + * "index": 1, + * "name": "No", + * "position_id": "0" + * } + * ], + * "question": "Will this test webhook fire correctly?", + * "title": "Test Market 0000", + * "description": "A test market for webhook payload verification.", + * "category": "Crypto", + * "tags": [ + * "test", + * "crypto" + * ], + * "image_url": null, + * "neg_risk": false + * } + * } + */ + WsAlertMarketCreatedEvent: { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "market_created"; + /** + * Format: int64 + * @description Unix timestamp in milliseconds + */ + timestamp: number; + data: components["schemas"]["MarketCreatedPayload"]; + }; + WsAlertAssetPriceTickSubscribeMessage: { + /** @enum {string} */ + op: "subscribe"; + /** @enum {string} */ + event: "asset_price_tick"; + } & components["schemas"]["AssetPriceTickFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "asset_price_tick"; + }; + WsAlertAssetPriceTickUnsubscribeMessage: { + /** @enum {string} */ + op: "unsubscribe"; + /** @enum {string} */ + event: "asset_price_tick"; + } & components["schemas"]["AssetPriceTickFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "asset_price_tick"; + }; + /** + * @description Pushed `asset_price_tick` alert. The `data` payload matches the corresponding HTTP webhook payload schema. + * @example { + * "event": "asset_price_tick", + * "timestamp": 1743500000000, + * "data": { + * "symbol": "BTC", + * "price": 65000, + * "timestamp_ms": 1700000000000 + * } + * } + */ + WsAlertAssetPriceTickEvent: { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "asset_price_tick"; + /** + * Format: int64 + * @description Unix timestamp in milliseconds + */ + timestamp: number; + data: components["schemas"]["AssetPriceTickPayload"]; + }; + WsAlertAssetPriceWindowUpdateSubscribeMessage: { + /** @enum {string} */ + op: "subscribe"; + /** @enum {string} */ + event: "asset_price_window_update"; + } & components["schemas"]["AssetPriceWindowUpdateFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "asset_price_window_update"; + }; + WsAlertAssetPriceWindowUpdateUnsubscribeMessage: { + /** @enum {string} */ + op: "unsubscribe"; + /** @enum {string} */ + event: "asset_price_window_update"; + } & components["schemas"]["AssetPriceWindowUpdateFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "asset_price_window_update"; + }; + /** + * @description Pushed `asset_price_window_update` alert. The `data` payload matches the corresponding HTTP webhook payload schema. + * @example { + * "event": "asset_price_window_update", + * "timestamp": 1743500000000, + * "data": { + * "symbol": "BTC", + * "variant": "1h", + * "start_time": 1700000000000, + * "end_time": 1700003600000, + * "open_price": 64800, + * "close_price": 65200, + * "update_type": "close" + * } + * } + */ + WsAlertAssetPriceWindowUpdateEvent: { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "asset_price_window_update"; + /** + * Format: int64 + * @description Unix timestamp in milliseconds + */ + timestamp: number; + data: components["schemas"]["AssetPriceWindowUpdatePayload"]; + }; + /** @description Typed subscribe request for the alerts WebSocket. The request shape depends on `event` and reuses the matching webhook filter schema. */ + WsAlertSubscribeMessage: components["schemas"]["WsAlertTraderFirstTradeSubscribeMessage"] | components["schemas"]["WsAlertTraderNewMarketSubscribeMessage"] | components["schemas"]["WsAlertTraderWhaleTradeSubscribeMessage"] | components["schemas"]["WsAlertTraderNewTradeSubscribeMessage"] | components["schemas"]["WsAlertTraderGlobalPnlSubscribeMessage"] | components["schemas"]["WsAlertTraderMarketPnlSubscribeMessage"] | components["schemas"]["WsAlertTraderEventPnlSubscribeMessage"] | components["schemas"]["WsAlertConditionMetricsSubscribeMessage"] | components["schemas"]["WsAlertEventMetricsSubscribeMessage"] | components["schemas"]["WsAlertPositionMetricsSubscribeMessage"] | components["schemas"]["WsAlertMarketVolumeMilestoneSubscribeMessage"] | components["schemas"]["WsAlertEventVolumeMilestoneSubscribeMessage"] | components["schemas"]["WsAlertPositionVolumeMilestoneSubscribeMessage"] | components["schemas"]["WsAlertProbabilitySpikeSubscribeMessage"] | components["schemas"]["WsAlertPriceSpikeSubscribeMessage"] | components["schemas"]["WsAlertMarketVolumeSpikeSubscribeMessage"] | components["schemas"]["WsAlertEventVolumeSpikeSubscribeMessage"] | components["schemas"]["WsAlertPositionVolumeSpikeSubscribeMessage"] | components["schemas"]["WsAlertCloseToBondSubscribeMessage"] | components["schemas"]["WsAlertMarketCreatedSubscribeMessage"] | components["schemas"]["WsAlertAssetPriceTickSubscribeMessage"] | components["schemas"]["WsAlertAssetPriceWindowUpdateSubscribeMessage"]; + /** @description Typed unsubscribe request for the alerts WebSocket. The request shape depends on `event` and must match the original subscription filters. */ + WsAlertUnsubscribeMessage: components["schemas"]["WsAlertTraderFirstTradeUnsubscribeMessage"] | components["schemas"]["WsAlertTraderNewMarketUnsubscribeMessage"] | components["schemas"]["WsAlertTraderWhaleTradeUnsubscribeMessage"] | components["schemas"]["WsAlertTraderNewTradeUnsubscribeMessage"] | components["schemas"]["WsAlertTraderGlobalPnlUnsubscribeMessage"] | components["schemas"]["WsAlertTraderMarketPnlUnsubscribeMessage"] | components["schemas"]["WsAlertTraderEventPnlUnsubscribeMessage"] | components["schemas"]["WsAlertConditionMetricsUnsubscribeMessage"] | components["schemas"]["WsAlertEventMetricsUnsubscribeMessage"] | components["schemas"]["WsAlertPositionMetricsUnsubscribeMessage"] | components["schemas"]["WsAlertMarketVolumeMilestoneUnsubscribeMessage"] | components["schemas"]["WsAlertEventVolumeMilestoneUnsubscribeMessage"] | components["schemas"]["WsAlertPositionVolumeMilestoneUnsubscribeMessage"] | components["schemas"]["WsAlertProbabilitySpikeUnsubscribeMessage"] | components["schemas"]["WsAlertPriceSpikeUnsubscribeMessage"] | components["schemas"]["WsAlertMarketVolumeSpikeUnsubscribeMessage"] | components["schemas"]["WsAlertEventVolumeSpikeUnsubscribeMessage"] | components["schemas"]["WsAlertPositionVolumeSpikeUnsubscribeMessage"] | components["schemas"]["WsAlertCloseToBondUnsubscribeMessage"] | components["schemas"]["WsAlertMarketCreatedUnsubscribeMessage"] | components["schemas"]["WsAlertAssetPriceTickUnsubscribeMessage"] | components["schemas"]["WsAlertAssetPriceWindowUpdateUnsubscribeMessage"]; + /** @description Typed pushed-event envelope for the alerts WebSocket. The `data` payload depends on `event` and matches the corresponding HTTP webhook payload schema. */ + WsAlertEventPayload: components["schemas"]["WsAlertTraderFirstTradeEvent"] | components["schemas"]["WsAlertTraderNewMarketEvent"] | components["schemas"]["WsAlertTraderWhaleTradeEvent"] | components["schemas"]["WsAlertTraderNewTradeEvent"] | components["schemas"]["WsAlertTraderGlobalPnlEvent"] | components["schemas"]["WsAlertTraderMarketPnlEvent"] | components["schemas"]["WsAlertTraderEventPnlEvent"] | components["schemas"]["WsAlertConditionMetricsEvent"] | components["schemas"]["WsAlertEventMetricsEvent"] | components["schemas"]["WsAlertPositionMetricsEvent"] | components["schemas"]["WsAlertMarketVolumeMilestoneEvent"] | components["schemas"]["WsAlertEventVolumeMilestoneEvent"] | components["schemas"]["WsAlertPositionVolumeMilestoneEvent"] | components["schemas"]["WsAlertProbabilitySpikeEvent"] | components["schemas"]["WsAlertPriceSpikeEvent"] | components["schemas"]["WsAlertMarketVolumeSpikeEvent"] | components["schemas"]["WsAlertEventVolumeSpikeEvent"] | components["schemas"]["WsAlertPositionVolumeSpikeEvent"] | components["schemas"]["WsAlertCloseToBondEvent"] | components["schemas"]["WsAlertMarketCreatedEvent"] | components["schemas"]["WsAlertAssetPriceTickEvent"] | components["schemas"]["WsAlertAssetPriceWindowUpdateEvent"]; + }; + responses: never; + parameters: never; + requestBodies: never; + headers: never; + pathItems: never; +} +export type $defs = Record; +export type operations = Record; + +export interface WsAlertSubscribeMap { + trader_first_trade: components["schemas"]["WsAlertTraderFirstTradeSubscribeMessage"]; + trader_new_market: components["schemas"]["WsAlertTraderNewMarketSubscribeMessage"]; + trader_whale_trade: components["schemas"]["WsAlertTraderWhaleTradeSubscribeMessage"]; + trader_new_trade: components["schemas"]["WsAlertTraderNewTradeSubscribeMessage"]; + trader_global_pnl: components["schemas"]["WsAlertTraderGlobalPnlSubscribeMessage"]; + trader_market_pnl: components["schemas"]["WsAlertTraderMarketPnlSubscribeMessage"]; + trader_event_pnl: components["schemas"]["WsAlertTraderEventPnlSubscribeMessage"]; + condition_metrics: components["schemas"]["WsAlertConditionMetricsSubscribeMessage"]; + event_metrics: components["schemas"]["WsAlertEventMetricsSubscribeMessage"]; + position_metrics: components["schemas"]["WsAlertPositionMetricsSubscribeMessage"]; + market_volume_milestone: components["schemas"]["WsAlertMarketVolumeMilestoneSubscribeMessage"]; + event_volume_milestone: components["schemas"]["WsAlertEventVolumeMilestoneSubscribeMessage"]; + position_volume_milestone: components["schemas"]["WsAlertPositionVolumeMilestoneSubscribeMessage"]; + probability_spike: components["schemas"]["WsAlertProbabilitySpikeSubscribeMessage"]; + price_spike: components["schemas"]["WsAlertPriceSpikeSubscribeMessage"]; + market_volume_spike: components["schemas"]["WsAlertMarketVolumeSpikeSubscribeMessage"]; + event_volume_spike: components["schemas"]["WsAlertEventVolumeSpikeSubscribeMessage"]; + position_volume_spike: components["schemas"]["WsAlertPositionVolumeSpikeSubscribeMessage"]; + close_to_bond: components["schemas"]["WsAlertCloseToBondSubscribeMessage"]; + market_created: components["schemas"]["WsAlertMarketCreatedSubscribeMessage"]; + asset_price_tick: components["schemas"]["WsAlertAssetPriceTickSubscribeMessage"]; + asset_price_window_update: components["schemas"]["WsAlertAssetPriceWindowUpdateSubscribeMessage"]; +} + +export interface WsAlertEventDataMap { + trader_first_trade: components["schemas"]["FirstTradePayload"]; + trader_new_market: components["schemas"]["NewMarketPayload"]; + trader_whale_trade: components["schemas"]["WhaleTradePayload"]; + trader_new_trade: components["schemas"]["NewTradePayload"]; + trader_global_pnl: components["schemas"]["GlobalPnlPayload"]; + trader_market_pnl: components["schemas"]["MarketPnlPayload"]; + trader_event_pnl: components["schemas"]["EventPnlPayload"]; + condition_metrics: components["schemas"]["ConditionMetricsPayload"]; + event_metrics: components["schemas"]["EventMetricsPayload"]; + position_metrics: components["schemas"]["PositionMetricsPayload"]; + market_volume_milestone: components["schemas"]["VolumeMilestonePayload"]; + event_volume_milestone: components["schemas"]["EventVolumeMilestonePayload"]; + position_volume_milestone: components["schemas"]["PositionVolumeMilestonePayload"]; + probability_spike: components["schemas"]["ProbabilitySpikePayload"]; + price_spike: components["schemas"]["PriceSpikePayload"]; + market_volume_spike: components["schemas"]["MarketVolumeSpikePayload"]; + event_volume_spike: components["schemas"]["EventVolumeSpikePayload"]; + position_volume_spike: components["schemas"]["PositionVolumeSpikePayload"]; + close_to_bond: components["schemas"]["CloseToBondPayload"]; + market_created: components["schemas"]["MarketCreatedPayload"]; + asset_price_tick: components["schemas"]["AssetPriceTickPayload"]; + asset_price_window_update: components["schemas"]["AssetPriceWindowUpdatePayload"]; +} + +export type WsAlertEventName = keyof WsAlertSubscribeMap; diff --git a/src/types/index.ts b/src/types/index.ts index 47a56c6..666038a 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -26,6 +26,7 @@ type TimeframeRecord = Partial>; export type BondMarket = Schemas["BondMarket"]; export type BondOutcome = Schemas["BondOutcome"]; export type CandlestickResolution = Schemas["CandlestickResolution"]; +export type ChartResolution = Schemas["ChartResolution"]; export type ClobReward = Schemas["ClobReward"]; export type ConditionMetricsResponse = Schemas["ConditionMetricsResponse"]; export type EventMarket = Schemas["EventMarket"]; @@ -97,6 +98,7 @@ export type MarketSortBy = Schemas["MarketSortBy"]; export type MarketStatus = Schemas["MarketStatus"]; export type OutcomeIndex = Schemas["OutcomeIndex"]; export type PositionChartDataPoint = Schemas["PositionChartDataPoint"]; +export type PositionStatus = Schemas["PositionStatus"]; export type TradeType = Schemas["TradeType"]; export type WebhookAssetSymbol = Schemas["WebhookAssetSymbol"]; export type WebhookTimeframe = Schemas["WebhookTimeframe"]; @@ -416,8 +418,23 @@ export type { TraderPositionsSubscribeFilters, TraderPositionsSubscribeResponse, TraderPositionUpdateEvent, + ClobRewardsSubscribeFilters, + ClobRewardsUpdateEvent, + ClobRewardsSubscribeResponse, WalletTrackingSubscribeFilters, + WalletTrackingSubscribeResponse, WalletTrackingAlertEvent, + WsAlertSubscribedResponse, + WsAlertUnsubscribedResponse, + WsAlertErrorResponse, + WsAlertEventType, + AlertsSubscribeFilters, + WsAlertSubscribeMessage, + WsAlertUnsubscribeMessage, + WsAlertEventPayload, + WsAlertSubscribeMap, + WsAlertEventDataMap, + WsAlertEventName, WsPredictionMarketMetadata, TradeStreamEvent, AssetPriceTickEvent, diff --git a/src/types/ws-helpers.ts b/src/types/ws-helpers.ts index a72eea8..7e9c9a3 100644 --- a/src/types/ws-helpers.ts +++ b/src/types/ws-helpers.ts @@ -1,3 +1,4 @@ -import type { components } from "../generated/ws.js"; +import type { components, WsAlertSubscribeMap, WsAlertEventDataMap, WsAlertEventName } from "../generated/ws.js"; export type WsSchemas = components["schemas"]; +export type { WsAlertSubscribeMap, WsAlertEventDataMap, WsAlertEventName }; diff --git a/src/types/ws.ts b/src/types/ws.ts index 344c1a2..1b3c39c 100644 --- a/src/types/ws.ts +++ b/src/types/ws.ts @@ -1,5 +1,5 @@ import type { RetryConfig } from "./http.js"; -import type { WsSchemas } from "./ws-helpers.js"; +import type { WsSchemas, WsAlertSubscribeMap, WsAlertEventDataMap, WsAlertEventName } from "./ws-helpers.js"; export type ConnectionState = "disconnected" | "connecting" | "connected" | "reconnecting"; @@ -21,9 +21,11 @@ export type WsRoomId = | "polymarket_trader_positions" | "polymarket_accounts" | "polymarket_order_book" - | "polymarket_wallet_tracking"; + | "polymarket_clob_rewards" + | "polymarket_wallet_tracking" + | "ws_alerts"; -export type WsFiltersOptionalRoom = "polymarket_asset_prices"; +export type WsFiltersOptionalRoom = "polymarket_asset_prices" | "polymarket_clob_rewards"; export type WsFiltersRequiredRoom = Exclude; export type TradesSubscribeFilters = Omit; @@ -37,7 +39,9 @@ export type AccountsSubscribeFilters = Pick>; export type OrderBookSubscribeFilters = Omit; export type TraderPositionsSubscribeFilters = Omit; +export type ClobRewardsSubscribeFilters = Omit; export type WalletTrackingSubscribeFilters = Omit; +export type AlertsSubscribeFilters = Omit; export type TradeStreamEvent = WsSchemas["TradeStreamEvent"]; export type AssetPriceTickEvent = WsSchemas["AssetPriceTickEvent"]; @@ -56,8 +60,19 @@ export type WsOrderBookLevel = WsSchemas["OrderBookLevel"]; export type OrderBookUpdateEvent = WsSchemas["OrderBookUpdateEvent"]; export type TraderPositionUpdateEvent = WsSchemas["TraderPositionUpdateEvent"]; export type TraderPositionsSubscribeResponse = WsSchemas["TraderPositionsSubscribeResponse"]; +export type ClobRewardsUpdateEvent = WsSchemas["ClobRewardsUpdateEvent"]; +export type ClobRewardsSubscribeResponse = WsSchemas["ClobRewardsSubscribeResponse"]; +export type WalletTrackingSubscribeResponse = WsSchemas["WalletTrackingSubscribeResponse"]; export type WalletTrackingAlertEvent = WsSchemas["WalletTrackingAlertEvent"]; +export type WsAlertSubscribeMessage = WsSchemas["WsAlertSubscribeMessage"]; +export type WsAlertUnsubscribeMessage = WsSchemas["WsAlertUnsubscribeMessage"]; +export type WsAlertEventPayload = WsSchemas["WsAlertEventPayload"]; +export type WsAlertSubscribedResponse = WsSchemas["WsAlertSubscribedResponse"]; +export type WsAlertUnsubscribedResponse = WsSchemas["WsAlertUnsubscribedResponse"]; +export type WsAlertErrorResponse = WsSchemas["WsAlertErrorResponse"]; +export type WsAlertEventType = WsSchemas["WsAlertEventType"]; export type WsPredictionMarketMetadata = WsSchemas["PredictionMarketMetadata"]; +export type { WsAlertSubscribeMap, WsAlertEventDataMap, WsAlertEventName }; export type TradesStreamSubscribeResponse = WsSchemas["TradesStreamSubscribeResponse"]; export type AssetPricesSubscribeResponse = WsSchemas["AssetPricesSubscribeResponse"]; @@ -85,7 +100,9 @@ export interface WebSocketEventMap { matic_update: MaticUpdateEvent; order_book_update: OrderBookUpdateEvent; trader_position_update: TraderPositionUpdateEvent; + clob_rewards_update: ClobRewardsUpdateEvent; wallet_tracking_alert: WalletTrackingAlertEvent; + ws_alert: WsAlertEventPayload; connected: void; disconnected: { code: number; reason: string }; reconnecting: { attempt: number }; @@ -103,7 +120,9 @@ export interface WsSubscriptionMap { polymarket_trader_positions: TraderPositionsSubscribeFilters; polymarket_accounts: AccountsSubscribeFilters; polymarket_order_book: OrderBookSubscribeFilters; + polymarket_clob_rewards: ClobRewardsSubscribeFilters; polymarket_wallet_tracking: WalletTrackingSubscribeFilters; + ws_alerts: AlertsSubscribeFilters; } export interface WsSubscribeResponseMap { @@ -117,5 +136,7 @@ export interface WsSubscribeResponseMap { polymarket_trader_positions: TraderPositionsSubscribeResponse; polymarket_accounts: AccountsSubscribeResponse; polymarket_order_book: OrderBookSubscribeResponse; - polymarket_wallet_tracking: Record; + polymarket_clob_rewards: ClobRewardsSubscribeResponse; + polymarket_wallet_tracking: WalletTrackingSubscribeResponse; + ws_alerts: WsAlertSubscribedResponse; } diff --git a/src/ws.ts b/src/ws.ts index 75f0c2f..c68b74f 100644 --- a/src/ws.ts +++ b/src/ws.ts @@ -9,7 +9,9 @@ import type { WsFiltersRequiredRoom, WsSubscriptionMap, WsSubscribeResponseMap, + WsAlertSubscribedResponse, } from "./types/ws.js"; +import type { WsAlertSubscribeMap, WsAlertEventName } from "./types/ws-helpers.js"; const DEFAULT_WS_URL = "wss://api.struct.to/ws"; const PING_INTERVAL_MS = 30_000; @@ -99,7 +101,8 @@ export class StructWebSocket { } subscribe(room: R, filters?: WsSubscriptionMap[R]): Promise; - subscribe(room: R, filters: WsSubscriptionMap[R]): Promise; + subscribe(room: "ws_alerts", filters: { event: E } & Omit): Promise; + subscribe>(room: R, filters: WsSubscriptionMap[R]): Promise; subscribe(room: R, filters?: WsSubscriptionMap[R]): Promise { const resolvedFilters = (filters ?? {}) as Record; const isNewRoom = !this.subscriptions.has(room); From e5ebc7a22a0c7fb6b9dddff54945e0c28aa6dcf0 Mon Sep 17 00:00:00 2001 From: elliotdotsol Date: Wed, 8 Apr 2026 03:54:24 +0700 Subject: [PATCH 09/12] update: ws --- .gitignore | 3 +- CLAUDE.md | 15 ++- README.md | 176 ++++++++++++++++++++++++++------ package.json | 11 +- scripts/check-routes.ts | 8 ++ scripts/fetch-specs.ts | 58 +++++++++++ src/index.ts | 1 + src/types/index.ts | 2 +- src/types/ws.ts | 18 ++-- src/ws-alerts.ts | 215 ++++++++++++++++++++++++++++++++++++++++ src/ws.ts | 11 +- 11 files changed, 458 insertions(+), 60 deletions(-) create mode 100644 scripts/fetch-specs.ts create mode 100644 src/ws-alerts.ts diff --git a/.gitignore b/.gitignore index 3705285..aac2149 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ dist/ .DS_Store .env logs/ -*.tgz \ No newline at end of file +*.tgz +openapi/.spec-source.json \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md index 851cbd3..c57847b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -11,17 +11,16 @@ TypeScript SDK (`@structbuild/sdk`) for prediction market APIs via `api.struct.t - **Build:** `bun run build` (outputs ESM + CJS to `dist/`, generates declaration files) - **Typecheck:** `bun run typecheck` - **Install deps:** `bun install` -- **Fetch OpenAPI spec:** `bun run fetch-spec:polymarket` -- **Generate types:** `bun run generate:polymarket` -- **Full pipeline:** `bun run prep` (fetch specs, generate types, check routes, build) -- **Check routes:** `bun run check-routes` (validates namespace routes match OpenAPI spec) -- **Fetch webhook spec:** `bun run fetch-spec:webhooks` -- **Generate webhook types:** `bun run generate:webhooks` -- **Fetch WS spec:** `bun run fetch-spec:ws` (AsyncAPI format) -- **Generate WS types:** `bun run generate:ws` +- **Fetch all specs:** `bun run fetch-specs` (fetches from production by default; use `STRUCT_ENV=staging` for staging) +- **Generate types:** `bun run generate:polymarket`, `bun run generate:webhooks`, `bun run generate:ws` +- **Full pipeline (prod):** `bun run prep` (fetch specs from prod, generate types, check routes, build) +- **Full pipeline (staging):** `bun run prep:staging` (same as prep but fetches from staging-api.struct.to) +- **Check routes:** `bun run check-routes` (validates namespace routes match OpenAPI spec; warns if specs are from staging) - **Fix spec:** `bun run fix-spec` (fixes broken `$ref`s in the OpenAPI spec) - **Test:** `bun test` (integration tests against live API, requires `STRUCT_API_KEY`) - **Test watch:** `bun test --watch` +- **Link for local dev:** `bun link` (then `bun link @structbuild/sdk` in consumer repo) +- **Pack for testing:** `bun run pack` (builds and creates `.tgz`) ## Architecture diff --git a/README.md b/README.md index 02392ae..177f8f4 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,6 @@ TypeScript SDK for prediction market data via [api.struct.to](https://api.struct ```bash npm install @structbuild/sdk # or -pnpm add @structbuild/sdk -# or bun add @structbuild/sdk ``` @@ -45,64 +43,71 @@ const client = new StructClient({ ```typescript const markets = await client.markets.getMarkets({ limit: 10 }); -const market = await client.markets.getMarket({ condition_id: "0x..." }); +const market = await client.markets.getMarket({ conditionId: "0x..." }); const marketBySlug = await client.markets.getMarketBySlug({ slug: "will-x-happen" }); const trades = await client.markets.getTrades({ condition_id: "0x..." }); -const candles = await client.markets.getCandlestick({ condition_id: "0x...", timeframe: "1d", interval: "1h" }); +const candles = await client.markets.getCandlestick({ condition_id: "0x...", fidelity: 60 }); const metrics = await client.markets.getMarketMetrics({ condition_id: "0x..." }); const volumeChart = await client.markets.getMarketVolumeChart({ condition_id: "0x..." }); +const priceJumps = await client.markets.getPriceJumps(); ``` ### Events ```typescript const events = await client.events.getEvents({ limit: 10 }); -const event = await client.events.getEvent({ id: "123" }); +const event = await client.events.getEvent({ identifier: "123" }); const eventBySlug = await client.events.getEventBySlug({ slug: "us-election" }); const eventMetrics = await client.events.getEventMetrics({ event_id: "123" }); +const chart = await client.events.getEventChart({ event_slug: "us-election" }); ``` ### Trader / Portfolio ```typescript -const portfolio = await client.trader.getPortfolio({ address: "0x..." }); -const positions = await client.trader.getPortfolioPositions({ address: "0x..." }); const trades = await client.trader.getTraderTrades({ address: "0x..." }); const profile = await client.trader.getTraderProfile({ address: "0x..." }); const pnl = await client.trader.getTraderPnl({ address: "0x..." }); -const pnlByMarket = await client.trader.getTraderMarketPnl({ address: "0x..." }); -const pnlByEvent = await client.trader.getTraderEventPnl({ address: "0x..." }); +const marketPnl = await client.trader.getTraderMarketPnl({ address: "0x..." }); +const eventPnl = await client.trader.getTraderEventPnl({ address: "0x..." }); +const outcomePnl = await client.trader.getTraderOutcomePnl({ address: "0x..." }); const pnlCandles = await client.trader.getTraderPnlCandles({ address: "0x..." }); +const pnlCalendar = await client.trader.getTraderPnlCalendar({ address: "0x..." }); const volumeChart = await client.trader.getTraderVolumeChart({ address: "0x..." }); +const leaderboard = await client.trader.getGlobalPnl(); ``` ### Holders ```typescript const marketHolders = await client.holders.getMarketHolders({ condition_id: "0x..." }); -const eventHolders = await client.holders.getEventHolders({ event_slug: "us-election" }); -const positionHolders = await client.holders.getPositionHolders({ position_id: "123" }); +const positionHolders = await client.holders.getPositionHolders({ positionId: "123" }); const history = await client.holders.getMarketHoldersHistory({ condition_id: "0x..." }); ``` -### Series +### Order Book ```typescript -const series = await client.series.getSeriesList(); -const outcomes = await client.series.getSeriesOutcomes({ series_slug: "my-series" }); +const orderBook = await client.orderBook.getOrderBook({ asset_id: "0x..." }); +const history = await client.orderBook.getOrderBookHistory(); +const marketBook = await client.orderBook.getMarketOrderBook(); +const spreads = await client.orderBook.getSpreadHistory(); ``` -### Search, Tags, Bonds +### Series, Search, Tags, Assets, Bonds ```typescript +const series = await client.series.getSeriesList(); +const outcomes = await client.series.getSeriesOutcomes({ series_slug: "my-series" }); const results = await client.search.search({ query: "election" }); const tags = await client.tags.getTags(); +const assetHistory = await client.assets.getAssetHistory({ asset_id: "0x..." }); const bonds = await client.bonds.getBonds(); ``` ### Webhooks -Manage webhook subscriptions for real-time event notifications. Webhook endpoints are platform-level (not venue-scoped). +Manage webhook subscriptions for real-time event notifications: ```typescript const webhooks = await client.webhooks.list(); @@ -114,30 +119,139 @@ const webhook = await client.webhooks.create({ min_usd_value: 100, }, }); -const detail = await client.webhooks.getWebhook({ webhookId: webhook.data.id }); -await client.webhooks.update({ webhookId: webhook.data.id, events: ["first_trade"] }); await client.webhooks.test({ webhookId: webhook.data.id }); await client.webhooks.deleteWebhook({ webhookId: webhook.data.id }); ``` -#### Webhook Payload Types +## WebSocket API -The SDK exports typed payload schemas for building webhook receivers: +Real-time streaming via room-based subscriptions with fully typed filters, responses, and events. ```typescript -import type { - FirstTradePayload, - ProbabilitySpikePayload, - GlobalPnlPayload, - VolumeMilestonePayload, -} from "@structbuild/sdk"; +import { StructWebSocket } from "@structbuild/sdk"; -function handleWebhook(payload: FirstTradePayload) { - console.log(payload.trader, payload.price, payload.side); -} +const ws = new StructWebSocket({ apiKey: "your-api-key" }); +await ws.connect(); +``` + +### Subscribing to rooms + +Each room has typed filters and a typed subscribe response: + +```typescript +const res = await ws.subscribe("polymarket_trades", { + condition_ids: ["0xabc123"], +}); + +await ws.subscribe("polymarket_order_book", { + asset_ids: ["0xabc123"], +}); + +// Some rooms have optional filters +await ws.subscribe("polymarket_asset_prices"); +await ws.subscribe("polymarket_clob_rewards", { subscribe_all: true }); +``` + +### Listening for events + +```typescript +ws.on("trade_stream_update", (event) => { + event.condition_id; + event.price; + event.size; + event.side; +}); + +ws.on("order_book_update", (event) => { + event.asset_id; + event.bids; + event.asks; +}); + +ws.on("clob_rewards_update", (event) => { + event.event_type; // "added" | "removed" | "updated" + event.condition_id; + event.reward; +}); +``` + +### Alerts + +Subscribe to typed alerts with per-event filter narrowing. TypeScript ensures you only use filters valid for the selected event: + +```typescript +await ws.subscribe("ws_alerts", { + event: "trader_whale_trade", + wallet_addresses: ["0xd91..."], + min_usd_value: 10000, +}); + +await ws.subscribe("ws_alerts", { + event: "probability_spike", + spike_direction: "up", + min_probability_change_pct: 5, +}); + +ws.on("ws_alert", (payload) => { + if (payload.event === "trader_whale_trade") { + payload.data.trader; + payload.data.amount_usd; + } + if (payload.event === "probability_spike") { + payload.data.spike_direction; + payload.data.spike_pct; + } +}); ``` -Available payload types: `FirstTradePayload`, `GlobalPnlPayload`, `MarketPnlPayload`, `EventPnlPayload`, `PositionPnlPayload`, `ConditionMetricsPayload`, `EventMetricsPayload`, `PositionMetricsPayload`, `VolumeMilestonePayload`, `EventVolumeMilestonePayload`, `PositionVolumeMilestonePayload`, `ProbabilitySpikePayload`. +### Wallet tracking + +```typescript +const res = await ws.subscribe("polymarket_wallet_tracking", { + wallet_addresses: ["0xd91..."], +}); +res.subscribed_count; +res.current_user_wallets; + +ws.on("wallet_tracking_alert", (event) => { + event.wallet_address; + event.trade; +}); +``` + +### Available rooms + +| Room | Filters | Event | +|------|---------|-------| +| `polymarket_trades` | `condition_ids` | `trade_stream_update` | +| `polymarket_asset_prices` | `condition_ids?` | `asset_price_tick`, `asset_price_window_update` | +| `polymarket_asset_window_updates` | `condition_ids` | `asset_window_update` | +| `polymarket_market_metrics` | `condition_ids` | `market_metrics_update` | +| `polymarket_event_metrics` | `event_slugs` | `event_metrics_update` | +| `polymarket_position_metrics` | `position_ids` | `position_metrics_update` | +| `polymarket_trader_pnl` | `addresses` | `trader_global_pnl_update`, `trader_market_pnl_update`, `trader_event_pnl_update` | +| `polymarket_trader_positions` | `addresses` | `trader_position_update` | +| `polymarket_accounts` | `wallets` | `accounts_update`, `usdce_update`, `matic_update` | +| `polymarket_order_book` | `asset_ids` | `order_book_update` | +| `polymarket_clob_rewards` | `condition_ids?`, `subscribe_all?` | `clob_rewards_update` | +| `polymarket_wallet_tracking` | `wallet_addresses` | `wallet_tracking_alert` | +| `ws_alerts` | per-event typed filters | `ws_alert` | + +### Lifecycle events + +```typescript +ws.on("connected", () => {}); +ws.on("disconnected", ({ code, reason }) => {}); +ws.on("reconnecting", ({ attempt }) => {}); +ws.on("error", (err) => {}); +``` + +### Cleanup + +```typescript +ws.unsubscribe("polymarket_trades"); +ws.disconnect(); +``` ## Pagination @@ -162,7 +276,7 @@ for await (const market of paginate( import { HttpError, TimeoutError, NetworkError } from "@structbuild/sdk"; try { - await client.markets.getMarket({ condition_id: "0x..." }); + await client.markets.getMarket({ conditionId: "0x..." }); } catch (error) { if (error instanceof HttpError) { console.log(error.status, error.body); diff --git a/package.json b/package.json index a729315..a489d67 100644 --- a/package.json +++ b/package.json @@ -24,16 +24,17 @@ "build": "rm -rf dist && bun build ./src/index.ts --target browser --format esm --sourcemap --outdir ./dist && bun build ./src/index.ts --target browser --format cjs --sourcemap --outdir ./dist-cjs && mv ./dist-cjs/index.js ./dist/index.cjs && mv ./dist-cjs/index.js.map ./dist/index.cjs.map && rm -rf dist-cjs && tsc --emitDeclarationOnly", "check-routes": "bun run scripts/check-routes.ts", "fix-spec": "bun run scripts/fix-spec.ts", - "prep": "bun run fetch-spec:polymarket && bun run fix-spec && bun run generate:polymarket && bun run fetch-spec:webhooks && bun run generate:webhooks && bun run fetch-spec:ws && bun run generate:ws && bun run check-routes && bun run build", + "fetch-specs": "bun run scripts/fetch-specs.ts", + "prep": "bun run fetch-specs && bun run fix-spec && bun run generate:polymarket && bun run generate:webhooks && bun run generate:ws && bun run check-routes && bun run build", + "prep:staging": "STRUCT_ENV=staging bun run prep", "test": "bun test", "test:watch": "bun test --watch", "typecheck": "bun run tsc -p tsconfig.check.json", - "fetch-spec:polymarket": "curl -s -o openapi/polymarket.json https://api.struct.to/api-docs/openapi.json", "generate:polymarket": "openapi-typescript openapi/polymarket.json -o src/generated/polymarket.ts", - "fetch-spec:webhooks": "curl -s -o openapi/webhooks.json https://api.struct.to/webhookopenapi.json", "generate:webhooks": "openapi-typescript openapi/webhooks.json -o src/generated/webhooks.ts", - "fetch-spec:ws": "curl -s --compressed -o openapi/ws.json https://staging-api.struct.to/asyncapi.json", - "generate:ws": "bun run scripts/generate-ws-types.ts" + "generate:ws": "bun run scripts/generate-ws-types.ts", + "link": "bun link", + "pack": "bun run build && bun pack" }, "devDependencies": { "@types/bun": "latest", diff --git a/scripts/check-routes.ts b/scripts/check-routes.ts index e6f2b99..92b20a0 100644 --- a/scripts/check-routes.ts +++ b/scripts/check-routes.ts @@ -244,4 +244,12 @@ if (missingWsSchemas.length > 0) { console.log(`\x1b[32m✓ [ws] All WS schemas exported.\x1b[0m`); } +const specSourcePath = join(import.meta.dirname, "../openapi/.spec-source.json"); +try { + const specSource = JSON.parse(await readFile(specSourcePath, "utf-8")); + if (specSource.env === "staging") { + console.warn(`\n\x1b[33m⚠ Specs were fetched from staging-api.struct.to. Run 'bun run prep' before merging.\x1b[0m\n`); + } +} catch {} + process.exit(hasErrors ? 1 : 0); diff --git a/scripts/fetch-specs.ts b/scripts/fetch-specs.ts new file mode 100644 index 0000000..2d35bb5 --- /dev/null +++ b/scripts/fetch-specs.ts @@ -0,0 +1,58 @@ +import { writeFile } from "node:fs/promises"; +import { join } from "node:path"; + +type Env = "production" | "staging"; + +const HOSTS: Record = { + production: "https://api.struct.to", + staging: "https://staging-api.struct.to", +}; + +const SPECS = [ + { name: "polymarket", path: "/api-docs/openapi.json", output: "openapi/polymarket.json" }, + { name: "webhooks", path: "/webhookopenapi.json", output: "openapi/webhooks.json" }, + { name: "ws", path: "/asyncapi.json", output: "openapi/ws.json" }, +] as const; + +const raw = (Bun.env.STRUCT_ENV ?? "production").toLowerCase(); +if (raw !== "production" && raw !== "staging") { + console.error(`Invalid STRUCT_ENV: "${raw}". Must be "production" or "staging".`); + process.exit(1); +} +const env = raw as Env; +const host = HOSTS[env]; + +const root = join(import.meta.dirname, ".."); + +let failed = false; +for (const spec of SPECS) { + const url = `${host}${spec.path}`; + try { + const res = await fetch(url, { + headers: { "Accept-Encoding": "gzip, deflate, br" }, + }); + if (!res.ok) { + console.error(`✗ ${spec.name}: HTTP ${res.status} from ${url}`); + failed = true; + continue; + } + const body = await res.text(); + JSON.parse(body); + await writeFile(join(root, spec.output), body); + console.log(`✓ ${spec.name}`); + } catch (err) { + console.error(`✗ ${spec.name}: ${err instanceof Error ? err.message : err}`); + failed = true; + } +} + +if (failed) { + process.exit(1); +} + +await writeFile( + join(root, "openapi/.spec-source.json"), + JSON.stringify({ env, fetchedAt: new Date().toISOString() }, null, 2) + "\n", +); + +console.log(`\nFetched all specs from ${env} (${host})`); diff --git a/src/index.ts b/src/index.ts index 2bb51ae..2ae9bb3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,6 +3,7 @@ export type { StructClientConfig } from "./client.js"; export { HttpClient } from "./http.js"; export { StructError, HttpError, NetworkError, TimeoutError, WebSocketError, WebSocketClosedError } from "./errors.js"; export { StructWebSocket } from "./ws.js"; +export { StructAlertsWebSocket } from "./ws-alerts.js"; export { paginate } from "./paginate.js"; export type { Venue } from "./types/common.js"; export type * from "./types/index.js"; diff --git a/src/types/index.ts b/src/types/index.ts index 666038a..4c90db4 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -400,6 +400,7 @@ export type { Address, PaginationParams, SortParams, Venue } from "./common.js"; export type { ConnectionState, StructWebSocketConfig, + AlertsWebSocketEventMap, WsRoomId, WsFiltersOptionalRoom, WsFiltersRequiredRoom, @@ -428,7 +429,6 @@ export type { WsAlertUnsubscribedResponse, WsAlertErrorResponse, WsAlertEventType, - AlertsSubscribeFilters, WsAlertSubscribeMessage, WsAlertUnsubscribeMessage, WsAlertEventPayload, diff --git a/src/types/ws.ts b/src/types/ws.ts index 1b3c39c..9c1f502 100644 --- a/src/types/ws.ts +++ b/src/types/ws.ts @@ -5,7 +5,7 @@ export type ConnectionState = "disconnected" | "connecting" | "connected" | "rec export interface StructWebSocketConfig { apiKey: string; - wsUrl?: string; + baseUrl?: string; reconnect?: RetryConfig; subscribeTimeout?: number; } @@ -22,8 +22,7 @@ export type WsRoomId = | "polymarket_accounts" | "polymarket_order_book" | "polymarket_clob_rewards" - | "polymarket_wallet_tracking" - | "ws_alerts"; + | "polymarket_wallet_tracking"; export type WsFiltersOptionalRoom = "polymarket_asset_prices" | "polymarket_clob_rewards"; export type WsFiltersRequiredRoom = Exclude; @@ -41,7 +40,6 @@ export type OrderBookSubscribeFilters = Omit; export type ClobRewardsSubscribeFilters = Omit; export type WalletTrackingSubscribeFilters = Omit; -export type AlertsSubscribeFilters = Omit; export type TradeStreamEvent = WsSchemas["TradeStreamEvent"]; export type AssetPriceTickEvent = WsSchemas["AssetPriceTickEvent"]; @@ -102,7 +100,6 @@ export interface WebSocketEventMap { trader_position_update: TraderPositionUpdateEvent; clob_rewards_update: ClobRewardsUpdateEvent; wallet_tracking_alert: WalletTrackingAlertEvent; - ws_alert: WsAlertEventPayload; connected: void; disconnected: { code: number; reason: string }; reconnecting: { attempt: number }; @@ -122,7 +119,6 @@ export interface WsSubscriptionMap { polymarket_order_book: OrderBookSubscribeFilters; polymarket_clob_rewards: ClobRewardsSubscribeFilters; polymarket_wallet_tracking: WalletTrackingSubscribeFilters; - ws_alerts: AlertsSubscribeFilters; } export interface WsSubscribeResponseMap { @@ -138,5 +134,13 @@ export interface WsSubscribeResponseMap { polymarket_order_book: OrderBookSubscribeResponse; polymarket_clob_rewards: ClobRewardsSubscribeResponse; polymarket_wallet_tracking: WalletTrackingSubscribeResponse; - ws_alerts: WsAlertSubscribedResponse; } + +export type AlertsWebSocketEventMap = { + [E in WsAlertEventName]: { event: E; timestamp: number; data: WsAlertEventDataMap[E] }; +} & { + connected: void; + disconnected: { code: number; reason: string }; + reconnecting: { attempt: number }; + error: Error; +}; diff --git a/src/ws-alerts.ts b/src/ws-alerts.ts new file mode 100644 index 0000000..7cb93cb --- /dev/null +++ b/src/ws-alerts.ts @@ -0,0 +1,215 @@ +import { WebSocketTransport } from "./ws-transport.js"; +import { WebSocketError } from "./errors.js"; +import type { + ConnectionState, + StructWebSocketConfig, + AlertsWebSocketEventMap, + WsAlertSubscribedResponse, +} from "./types/ws.js"; +import type { WsAlertSubscribeMap, WsAlertEventName } from "./types/ws-helpers.js"; + +const DEFAULT_BASE_URL = "wss://api.struct.to"; +const PING_INTERVAL_MS = 30_000; +const DEFAULT_SUBSCRIBE_TIMEOUT_MS = 10_000; + +type Listener = (payload: T) => void; + +interface PendingSubscribe { + resolve: (data: unknown) => void; + reject: (err: Error) => void; + timer: ReturnType; +} + +export class StructAlertsWebSocket { + private readonly transport: WebSocketTransport; + private readonly listeners = new Map>(); + private readonly subscriptions = new Map>(); + private readonly pendingSubscribes = new Map(); + private readonly subscribeTimeout: number; + private pingTimer: ReturnType | null = null; + + constructor(config: StructWebSocketConfig) { + this.subscribeTimeout = config.subscribeTimeout ?? DEFAULT_SUBSCRIBE_TIMEOUT_MS; + const base = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, ""); + const url = `${base}/v1/ws/alerts?api-key=${encodeURIComponent(config.apiKey)}`; + + this.transport = new WebSocketTransport( + url, + config.reconnect ?? {}, + { + onOpen: () => this.handleOpen(), + onClose: (code, reason) => this.handleClose(code, reason), + onError: (error) => this.emit("error", error), + onMessage: (data) => this.handleMessage(data), + onReconnecting: (attempt) => this.emit("reconnecting", { attempt }), + }, + ); + } + + get state(): ConnectionState { + return this.transport.state; + } + + connect(): Promise { + return this.transport.connect(); + } + + disconnect(): void { + this.stopPing(); + for (const [, pending] of this.pendingSubscribes) { + clearTimeout(pending.timer); + pending.reject(new WebSocketError("Disconnected")); + } + this.pendingSubscribes.clear(); + this.subscriptions.clear(); + this.transport.disconnect(); + } + + on(event: K, listener: Listener): () => void { + let set = this.listeners.get(event as string); + if (!set) { + set = new Set(); + this.listeners.set(event as string, set); + } + set.add(listener); + return () => { set.delete(listener); }; + } + + off(event: K, listener: Listener): void { + this.listeners.get(event as string)?.delete(listener); + } + + once(event: K, listener: Listener): () => void { + const wrapper = (payload: AlertsWebSocketEventMap[K]) => { + this.off(event, wrapper); + listener(payload); + }; + return this.on(event, wrapper); + } + + removeAllListeners(event?: keyof AlertsWebSocketEventMap): void { + if (event) { + this.listeners.delete(event as string); + } else { + this.listeners.clear(); + } + } + + subscribe( + event: E, + filters: Omit, + ): Promise { + const message = { op: "subscribe", event, ...filters } as Record; + this.subscriptions.set(event, message); + this.rebuildReplay(); + + this.transport.send(message); + + const existing = this.pendingSubscribes.get(event); + if (existing) { + clearTimeout(existing.timer); + existing.reject(new WebSocketError("Superseded by new subscription")); + } + + return new Promise((resolve, reject) => { + const timer = setTimeout(() => { + this.pendingSubscribes.delete(event); + reject(new WebSocketError(`Subscribe to alert ${event} timed out`)); + }, this.subscribeTimeout); + + this.pendingSubscribes.set(event, { + resolve: resolve as (data: unknown) => void, + reject, + timer, + }); + }); + } + + unsubscribe(event: WsAlertEventName): void { + const sub = this.subscriptions.get(event); + if (!sub) return; + + const pending = this.pendingSubscribes.get(event); + if (pending) { + clearTimeout(pending.timer); + pending.reject(new WebSocketError("Unsubscribed")); + this.pendingSubscribes.delete(event); + } + + this.transport.send({ ...sub, op: "unsubscribe" }); + this.subscriptions.delete(event); + this.rebuildReplay(); + } + + private rebuildReplay(): void { + this.transport.clearReplayMessages(); + for (const [, message] of this.subscriptions) { + this.transport.addReplayMessage(message); + } + } + + private handleOpen(): void { + this.startPing(); + this.emit("connected", undefined as never); + } + + private handleClose(code: number, reason: string): void { + this.stopPing(); + this.emit("disconnected", { code, reason }); + } + + private handleMessage(raw: unknown): void { + const msg = raw as { op?: string; event?: string; error?: string; subscription_id?: string; timestamp?: number; data?: unknown }; + if (!msg || typeof msg !== "object") return; + if (msg.op === "pong") return; + + if (msg.error) { + this.emit("error", new WebSocketError(msg.error)); + return; + } + + if (msg.op === "subscribed" && msg.event) { + const pending = this.pendingSubscribes.get(msg.event as WsAlertEventName); + if (pending) { + clearTimeout(pending.timer); + this.pendingSubscribes.delete(msg.event as WsAlertEventName); + pending.resolve({ op: "subscribed", event: msg.event, subscription_id: msg.subscription_id }); + } + return; + } + + if (msg.op === "unsubscribed") return; + + if (msg.event && msg.data !== undefined) { + this.emit(msg.event as keyof AlertsWebSocketEventMap, { + event: msg.event, + timestamp: msg.timestamp, + data: msg.data, + } as never); + } + } + + private emit(event: K, payload: AlertsWebSocketEventMap[K]): void { + const set = this.listeners.get(event as string); + if (!set) return; + for (const fn of set) { + try { + (fn as Listener)(payload); + } catch {} + } + } + + private startPing(): void { + this.stopPing(); + this.pingTimer = setInterval(() => { + this.transport.send({ type: "ping" }); + }, PING_INTERVAL_MS); + } + + private stopPing(): void { + if (this.pingTimer !== null) { + clearInterval(this.pingTimer); + this.pingTimer = null; + } + } +} diff --git a/src/ws.ts b/src/ws.ts index c68b74f..499fa62 100644 --- a/src/ws.ts +++ b/src/ws.ts @@ -9,11 +9,9 @@ import type { WsFiltersRequiredRoom, WsSubscriptionMap, WsSubscribeResponseMap, - WsAlertSubscribedResponse, } from "./types/ws.js"; -import type { WsAlertSubscribeMap, WsAlertEventName } from "./types/ws-helpers.js"; -const DEFAULT_WS_URL = "wss://api.struct.to/ws"; +const DEFAULT_BASE_URL = "wss://api.struct.to"; const PING_INTERVAL_MS = 30_000; const DEFAULT_SUBSCRIBE_TIMEOUT_MS = 10_000; @@ -35,8 +33,8 @@ export class StructWebSocket { constructor(config: StructWebSocketConfig) { this.subscribeTimeout = config.subscribeTimeout ?? DEFAULT_SUBSCRIBE_TIMEOUT_MS; - const wsUrl = (config.wsUrl ?? DEFAULT_WS_URL).replace(/\/+$/, ""); - const url = `${wsUrl}?api-key=${encodeURIComponent(config.apiKey)}`; + const base = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, ""); + const url = `${base}/ws?api-key=${encodeURIComponent(config.apiKey)}`; this.transport = new WebSocketTransport( url, @@ -101,8 +99,7 @@ export class StructWebSocket { } subscribe(room: R, filters?: WsSubscriptionMap[R]): Promise; - subscribe(room: "ws_alerts", filters: { event: E } & Omit): Promise; - subscribe>(room: R, filters: WsSubscriptionMap[R]): Promise; + subscribe(room: R, filters: WsSubscriptionMap[R]): Promise; subscribe(room: R, filters?: WsSubscriptionMap[R]): Promise { const resolvedFilters = (filters ?? {}) as Record; const isNewRoom = !this.subscriptions.has(room); From 318c0771fd4d081eaae232969b7561ca38d9de54 Mon Sep 17 00:00:00 2001 From: elliotdotsol Date: Fri, 10 Apr 2026 20:12:56 +0700 Subject: [PATCH 10/12] update: ws --- README.md | 16 - openapi/ws.json | 1586 ++++++++++++++++++++++++++++----------- package.json | 2 +- scripts/check-routes.ts | 7 + src/generated/ws.ts | 403 +++++++--- src/types/index.ts | 4 - src/types/ws.ts | 10 +- src/ws-alerts.ts | 2 +- 8 files changed, 1456 insertions(+), 574 deletions(-) diff --git a/README.md b/README.md index 850955e..5c5ead4 100644 --- a/README.md +++ b/README.md @@ -248,21 +248,6 @@ ws.on("ws_alert", (payload) => { }); ``` -### Wallet tracking - -```typescript -const res = await ws.subscribe("polymarket_wallet_tracking", { - wallet_addresses: ["0xd91..."], -}); -res.subscribed_count; -res.current_user_wallets; - -ws.on("wallet_tracking_alert", (event) => { - event.wallet_address; - event.trade; -}); -``` - ### Available rooms | Room | Filters | Event | @@ -278,7 +263,6 @@ ws.on("wallet_tracking_alert", (event) => { | `polymarket_accounts` | `wallets` | `accounts_update`, `usdce_update`, `matic_update` | | `polymarket_order_book` | `asset_ids` | `order_book_update` | | `polymarket_clob_rewards` | `condition_ids?`, `subscribe_all?` | `clob_rewards_update` | -| `polymarket_wallet_tracking` | `wallet_addresses` | `wallet_tracking_alert` | | `ws_alerts` | per-event typed filters | `ws_alert` | ### Lifecycle events diff --git a/openapi/ws.json b/openapi/ws.json index 4fffd54..a5bf4fa 100644 --- a/openapi/ws.json +++ b/openapi/ws.json @@ -24,7 +24,7 @@ "address": "polymarket_trades", "title": "Trades", "summary": "Trades stream", - "description": "Real-time stream of matched Polymarket prediction-market trades. At least one filter is required — open-ended subscriptions are rejected to prevent fan-out across all trades.\n\n**Filters (at least one required):**\n- `condition_ids` — 64-char hex condition IDs (with or without `0x` prefix)\n- `market_slugs` — market slugs\n- `event_slugs` — event slugs (delivers all markets under each event)\n- `position_ids` — ERC-1155 token IDs (decimal or hex)\n- `trade_types` — optional allowlist of trade types (e.g. `[\"OrderFilled\", \"OrdersMatched\"]`). Omit or pass `[]` for all types.\n\n**Unsubscribe:** Send `action: \"unsubscribe_all\"` to clear all subscriptions.", + "description": "Real-time stream of Polymarket prediction-market events (trades + oracle lifecycle). Supports both confirmed (on-chain) and pending (mempool) trades.\n\n**Filters (optional):**\n- `condition_ids` — 64-char hex condition IDs (with or without `0x` prefix)\n- `market_slugs` — market slugs\n- `event_slugs` — event slugs (delivers all markets under each event)\n- `position_ids` — ERC-1155 token IDs (decimal or hex)\n- `traders` — trader wallet addresses\n- `trade_types` — optional allowlist (e.g. `[\"OrderFilled\", \"Resolution\"]`). Omit or pass `[]` for all types.\n- `status` — `\"confirmed\"` (default), `\"pending\"`, or `\"all\"`\n\nIf no filters are provided, subscribes to ALL trades (open-ended).\n\n**Pending trades:** Fields unavailable from mempool (`block`, `confirmed_at`, `log_index`, `block_index`, `order_hash`, `taker`, `fee`, `fee_shares`, `fee_pct`) are omitted. `received_at` (ms) is included instead.\n\n**Unsubscribe:** Send `action: \"unsubscribe_all\"` to clear all subscriptions.", "messages": { "subscribe": { "$ref": "#/components/messages/TradesStreamSubscribe" @@ -112,7 +112,7 @@ "address": "polymarket_position_metrics", "title": "Position Metrics", "summary": "Position (outcome token) metrics stream", - "description": "Real-time volume, trade-count, and OHLC price/probability metrics per outcome-token position, across multiple timeframes. One event is pushed per timeframe window on each update.\n\n**Filter (required):** `position_ids` — ERC-1155 token IDs (decimal or hex; normalized to decimal strings internally).\n\n**Unsubscribe:** Send `action: \"unsubscribe_all\"`.", + "description": "Real-time volume, trade-count, and OHLC price/probability metrics per outcome-token position, across multiple timeframes. One event is pushed per timeframe window on each update.\n\n**Filter (required):** `position_ids` — ERC-1155 token IDs (decimal or hex).\n\n**Unsubscribe:** Send `action: \"unsubscribe_all\"`.", "messages": { "subscribe": { "$ref": "#/components/messages/PositionMetricsSubscribe" @@ -152,7 +152,7 @@ "address": "polymarket_trader_positions", "title": "Trader Positions", "summary": "Trader position updates stream", - "description": "Real-time position updates for tracked traders. Streams full position snapshots whenever a position PnL changes in the database.\n\n**Filter (required):** `traders` — EVM wallet addresses. Invalid addresses are returned in `rejected`.\n\n**Events pushed:** `trader_position_update` — includes PnL fields, shares balance, market slug, outcome, and all enriched data.\n\n**Unsubscribe:** Send `action: \"unsubscribe_all\"`.", + "description": "Real-time position updates for tracked traders. Streams full position snapshots whenever a position PnL changes.\n\n**Filter (required):** `traders` — EVM wallet addresses. Invalid addresses are returned in `rejected`.\n\n**Events pushed:** `trader_position_update` — includes PnL fields, shares balance, market slug, outcome, and all enriched data.\n\n**Unsubscribe:** Send `action: \"unsubscribe_all\"`.", "messages": { "subscribe": { "$ref": "#/components/messages/TraderPositionsSubscribe" @@ -222,23 +222,6 @@ } } }, - "polymarket_wallet_tracking": { - "address": "polymarket_wallet_tracking", - "title": "Wallet Tracking", - "summary": "Wallet trade tracking stream", - "description": "Real-time trade alerts for tracked Polymarket wallets. Streams a `wallet_tracking_alert` event whenever a subscribed wallet executes a trade, enriched with market metadata (slug, question, outcome, image).\n\n**Filter (required):** `wallet_addresses` — EVM wallet addresses to track.\n\n**Unsubscribe:** Disconnect or re-subscribe with a new address list.", - "messages": { - "subscribe": { - "$ref": "#/components/messages/WalletTrackingSubscribe" - }, - "subscribeResponse": { - "$ref": "#/components/messages/WalletTrackingSubscribeResponse" - }, - "walletTrackingAlertEvent": { - "$ref": "#/components/messages/WalletTrackingAlertEvent" - } - } - }, "ws_alerts": { "address": "/v1/ws/alerts", "title": "WebSocket Alerts", @@ -584,33 +567,6 @@ } ] }, - "subscribePolymarketWalletTracking": { - "action": "send", - "channel": { - "$ref": "#/channels/polymarket_wallet_tracking" - }, - "summary": "Subscribe to wallet trade tracking stream", - "messages": [ - { - "$ref": "#/channels/polymarket_wallet_tracking/messages/subscribe" - } - ] - }, - "receivePolymarketWalletTracking": { - "action": "receive", - "channel": { - "$ref": "#/channels/polymarket_wallet_tracking" - }, - "summary": "Receive wallet trade tracking stream events", - "messages": [ - { - "$ref": "#/channels/polymarket_wallet_tracking/messages/subscribeResponse" - }, - { - "$ref": "#/channels/polymarket_wallet_tracking/messages/walletTrackingAlertEvent" - } - ] - }, "subscribeWsAlerts": { "action": "send", "channel": { @@ -657,7 +613,7 @@ } }, "TradeStreamEvent": { - "summary": "a matched trade on a subscribed market/position/event/slug", + "summary": "Server-pushed event. Discriminated by `trade_type` — each variant only includes relevant fields.\n\nEnvelope: `{\"type\": \"trade_stream_update\", \"room_id\": \"polymarket_trades\", \"status\": \"confirmed\"|\"pending\", \"data\": {...}}`\n\n**Pending trades:** `block`, `confirmed_at`, `log_index`, `block_index` are absent. `received_at` (milliseconds) is included instead. For OrderFilled/OrdersMatched, `order_hash`, `taker`, `fee`, `fee_shares`, `fee_pct` are also absent", "payload": { "$ref": "#/components/schemas/TradeStreamEvent" } @@ -878,24 +834,6 @@ "$ref": "#/components/schemas/ClobRewardsSubscribeResponse" } }, - "WalletTrackingSubscribe": { - "summary": "Subscribe to wallet trade tracking stream", - "payload": { - "$ref": "#/components/schemas/WalletTrackingSubscribeMessage" - } - }, - "WalletTrackingAlertEvent": { - "summary": "a trade executed by a tracked wallet", - "payload": { - "$ref": "#/components/schemas/WalletTrackingAlertEvent" - } - }, - "WalletTrackingSubscribeResponse": { - "summary": "Subscription acknowledgement for wallet trade tracking stream", - "payload": { - "$ref": "#/components/schemas/WalletTrackingSubscribeResponse" - } - }, "WsAlertSubscribe": { "summary": "Subscribe to an alert event type", "payload": { @@ -1170,7 +1108,7 @@ }, "TradesStreamSubscribeMessage": { "type": "object", - "description": "Subscribe to the trades stream. At least one filter field must be non-empty.", + "description": "Subscribe to the trades stream. No filters = subscribe to all trades.", "required": [ "action" ], @@ -1210,21 +1148,58 @@ }, "description": "ERC-1155 outcome token IDs (decimal or hex strings)" }, + "traders": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Trader wallet addresses (lowercase 0x-prefixed)" + }, "trade_types": { "type": "array", "items": { "type": "string", "enum": [ "OrderFilled", + "OrdersMatched", "Redemption", "Merge", "Split", "Cancelled", "PositionsConverted", - "OrdersMatched" + "Initialization", + "Proposal", + "Dispute", + "Settled", + "Resolution", + "ConditionResolution", + "Reset", + "Flag", + "Unflag", + "Pause", + "Unpause", + "ManualResolution", + "NegRiskOutcomeReported", + "RegisterToken", + "Approval" ] }, - "description": "Only receive trades of these types. Empty array = all types." + "description": "Only receive events of these types. Empty array = all types." + }, + "status": { + "type": "string", + "enum": [ + "confirmed", + "pending", + "all" + ], + "default": "confirmed", + "description": "Trade status filter: \"confirmed\" (default) = on-chain only, \"pending\" = mempool only, \"all\" = both" + }, + "subscribe_all": { + "type": "boolean", + "default": false, + "description": "Explicitly subscribe to all trades. Also implicitly true when no filters are provided." } } }, @@ -1256,194 +1231,1126 @@ "type": "string" } }, + "traders": { + "type": "array", + "items": { + "type": "string" + } + }, "trade_types": { "type": "array", "items": { "type": "string" } }, + "status": { + "type": "string", + "enum": [ + "confirmed", + "pending", + "all" + ] + }, + "subscribe_all": { + "type": "boolean" + }, "rejected": { "type": "array", "items": { "type": "string" }, - "description": "Filter values that were rejected (invalid format or unknown trade type)" + "description": "Filter values that were rejected (invalid format or unknown type)" } } }, "TradeStreamEvent": { - "type": "object", - "description": "Server-pushed event: a matched trade on a subscribed market/position/event/slug. Envelope type: \"trade_stream_update\".", - "required": [ - "id", - "trader", - "taker", - "position_id", - "hash", - "block", - "confirmed_at", - "usd_amount", - "shares_amount", - "fee", - "price" - ], - "properties": { - "id": { - "type": "string", - "description": "Trade ID" - }, - "hash": { - "type": "string", - "description": "Transaction hash (hex)" - }, - "chain_id": { - "type": "integer", - "format": "uint64" - }, - "block": { - "type": "integer", - "format": "uint64" - }, - "confirmed_at": { - "type": "integer", - "format": "uint64", - "description": "Unix seconds" - }, - "log_index": { - "type": "integer", - "format": "uint64" - }, - "block_index": { - "type": "integer", - "format": "uint64" - }, - "order_hash": { - "type": "string", - "description": "Order hash (hex)" - }, - "trader": { - "type": "string", - "description": "Limit-order maker wallet address" - }, - "taker": { - "type": "string", - "description": "Order taker wallet address" - }, - "side": { - "type": [ - "string", - "null" - ], - "description": "\"Buy\" or \"Sell\" (null for non-trade operations like Redemption, Merge, Split)" - }, - "condition_id": { - "type": [ - "string", - "null" - ], - "description": "64-char hex condition ID" - }, - "position_id": { - "type": "string", - "description": "ERC-1155 outcome token ID (decimal string)" - }, - "outcome": { - "type": [ - "string", - "null" - ], - "description": "Outcome name (e.g. \"Yes\")" - }, - "outcome_index": { - "type": [ - "integer", - "null" - ], - "description": "0 = Yes, 1 = No" - }, - "question": { - "type": [ - "string", - "null" - ] - }, - "slug": { - "type": [ - "string", - "null" + "description": "Server-pushed event. Discriminated by `trade_type` — each variant only includes relevant fields.\n\nEnvelope: `{\"type\": \"trade_stream_update\", \"room_id\": \"polymarket_trades\", \"status\": \"confirmed\"|\"pending\", \"data\": {...}}`\n\n**Pending trades:** `block`, `confirmed_at`, `log_index`, `block_index` are absent. `received_at` (milliseconds) is included instead. For OrderFilled/OrdersMatched, `order_hash`, `taker`, `fee`, `fee_shares`, `fee_pct` are also absent.", + "oneOf": [ + { + "title": "OrderFilled / OrdersMatched", + "description": "A buy/sell trade was matched on the exchange.", + "type": "object", + "required": [ + "trade_type", + "id", + "hash", + "trader", + "exchange" ], - "description": "Market slug" - }, - "event_slug": { - "type": [ - "string", - "null" - ] - }, - "usd_amount": { - "type": "string", - "description": "USD value of the trade (decimal string)" - }, - "shares_amount": { - "type": "string", - "description": "Number of shares traded (decimal string)" - }, - "price": { - "type": "number", - "minimum": 0.0, - "maximum": 1.0, - "description": "Trade price (0–1)" + "properties": { + "trade_type": { + "type": "string", + "enum": [ + "OrderFilled", + "OrdersMatched" + ] + }, + "id": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "block": { + "type": "integer", + "description": "Absent for pending trades" + }, + "confirmed_at": { + "type": "integer", + "description": "Unix seconds. Absent for pending trades" + }, + "received_at": { + "type": "integer", + "description": "Unix milliseconds. Present for pending trades only" + }, + "log_index": { + "type": "integer", + "description": "Absent for pending trades" + }, + "block_index": { + "type": "integer", + "description": "Absent for pending trades" + }, + "order_hash": { + "type": "string", + "description": "Absent for pending trades" + }, + "trader": { + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "pseudonym": { + "type": [ + "string", + "null" + ] + }, + "profile_image": { + "type": [ + "string", + "null" + ] + }, + "x_username": { + "type": [ + "string", + "null" + ] + }, + "verified_badge": { + "type": "boolean" + } + } + }, + "taker": { + "type": "string", + "description": "Absent for pending trades" + }, + "side": { + "type": "string", + "enum": [ + "Buy", + "Sell" + ] + }, + "condition_id": { + "type": [ + "string", + "null" + ] + }, + "position_id": { + "type": "string" + }, + "outcome": { + "type": [ + "string", + "null" + ] + }, + "outcome_index": { + "type": [ + "integer", + "null" + ] + }, + "question": { + "type": [ + "string", + "null" + ] + }, + "image_url": { + "type": [ + "string", + "null" + ] + }, + "slug": { + "type": [ + "string", + "null" + ] + }, + "event_slug": { + "type": [ + "string", + "null" + ] + }, + "usd_amount": { + "type": "number" + }, + "shares_amount": { + "type": "number" + }, + "price": { + "type": "number" + }, + "probability": { + "type": [ + "number", + "null" + ] + }, + "fee": { + "type": "number", + "description": "Absent for pending trades" + }, + "fee_shares": { + "type": "number", + "description": "Absent for pending trades" + }, + "fee_pct": { + "type": "number", + "description": "Absent for pending trades" + }, + "exchange": { + "type": "integer" + } + } }, - "probability": { - "type": [ - "number", - "null" + { + "title": "Redemption", + "description": "Positions redeemed after market resolution.", + "type": "object", + "required": [ + "trade_type", + "id", + "hash", + "trader", + "exchange" ], - "description": "Implied probability (0–1)" - }, - "fee": { - "type": "string", - "description": "Protocol fee paid (decimal string)" - }, - "exchange": { - "type": "string", - "description": "Exchange identifier" - }, - "trade_type": { - "type": "string", - "description": "\"OrderFilled\", \"Redemption\", \"Merge\", \"Split\", \"Cancelled\", \"PositionsConverted\", \"OrdersMatched\"" - }, - "winning_outcome_index": { - "type": [ - "integer", - "null" + "properties": { + "trade_type": { + "type": "string", + "enum": [ + "Redemption" + ] + }, + "id": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "block": { + "type": "integer" + }, + "confirmed_at": { + "type": "integer" + }, + "received_at": { + "type": "integer" + }, + "log_index": { + "type": "integer" + }, + "block_index": { + "type": "integer" + }, + "trader": { + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "pseudonym": { + "type": [ + "string", + "null" + ] + }, + "profile_image": { + "type": [ + "string", + "null" + ] + }, + "x_username": { + "type": [ + "string", + "null" + ] + }, + "verified_badge": { + "type": "boolean" + } + } + }, + "condition_id": { + "type": [ + "string", + "null" + ] + }, + "outcome": { + "type": [ + "string", + "null" + ] + }, + "outcome_index": { + "type": [ + "integer", + "null" + ] + }, + "question": { + "type": [ + "string", + "null" + ] + }, + "image_url": { + "type": [ + "string", + "null" + ] + }, + "slug": { + "type": [ + "string", + "null" + ] + }, + "event_slug": { + "type": [ + "string", + "null" + ] + }, + "usd_amount": { + "type": "number" + }, + "winning_outcome_index": { + "type": [ + "integer", + "null" + ] + }, + "position_details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "position_id": { + "type": "string" + }, + "outcome_index": { + "type": "integer" + }, + "amount": { + "type": "string" + } + } + } + }, + "exchange": { + "type": "integer" + } + } + }, + { + "title": "Merge", + "description": "Outcome tokens burned to receive collateral.", + "type": "object", + "required": [ + "trade_type", + "id", + "hash", + "trader", + "exchange" ], - "description": "Resolved winning outcome index" + "properties": { + "trade_type": { + "type": "string", + "enum": [ + "Merge" + ] + }, + "id": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "block": { + "type": "integer" + }, + "confirmed_at": { + "type": "integer" + }, + "received_at": { + "type": "integer" + }, + "log_index": { + "type": "integer" + }, + "block_index": { + "type": "integer" + }, + "trader": { + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "pseudonym": { + "type": [ + "string", + "null" + ] + }, + "profile_image": { + "type": [ + "string", + "null" + ] + }, + "x_username": { + "type": [ + "string", + "null" + ] + }, + "verified_badge": { + "type": "boolean" + } + } + }, + "condition_id": { + "type": [ + "string", + "null" + ] + }, + "question": { + "type": [ + "string", + "null" + ] + }, + "image_url": { + "type": [ + "string", + "null" + ] + }, + "slug": { + "type": [ + "string", + "null" + ] + }, + "event_slug": { + "type": [ + "string", + "null" + ] + }, + "usd_amount": { + "type": "number" + }, + "position_details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "position_id": { + "type": "string" + }, + "outcome_index": { + "type": "integer" + }, + "amount": { + "type": "string" + } + } + } + }, + "exchange": { + "type": "integer" + } + } }, - "is_known_surebet": { - "type": "boolean" + { + "title": "Split", + "description": "Collateral deposited to receive outcome tokens.", + "type": "object", + "required": [ + "trade_type", + "id", + "hash", + "trader", + "exchange" + ], + "properties": { + "trade_type": { + "type": "string", + "enum": [ + "Split" + ] + }, + "id": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "block": { + "type": "integer" + }, + "confirmed_at": { + "type": "integer" + }, + "received_at": { + "type": "integer" + }, + "log_index": { + "type": "integer" + }, + "block_index": { + "type": "integer" + }, + "trader": { + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "pseudonym": { + "type": [ + "string", + "null" + ] + }, + "profile_image": { + "type": [ + "string", + "null" + ] + }, + "x_username": { + "type": [ + "string", + "null" + ] + }, + "verified_badge": { + "type": "boolean" + } + } + }, + "condition_id": { + "type": [ + "string", + "null" + ] + }, + "question": { + "type": [ + "string", + "null" + ] + }, + "image_url": { + "type": [ + "string", + "null" + ] + }, + "slug": { + "type": [ + "string", + "null" + ] + }, + "event_slug": { + "type": [ + "string", + "null" + ] + }, + "usd_amount": { + "type": "number" + }, + "position_details": { + "type": "array", + "items": { + "type": "object", + "properties": { + "position_id": { + "type": "string" + }, + "outcome_index": { + "type": "integer" + }, + "amount": { + "type": "string" + } + } + } + }, + "exchange": { + "type": "integer" + } + } }, - "is_coordinated": { - "type": "boolean" + { + "title": "PositionsConverted", + "description": "NegRisk NO tokens converted to YES tokens + collateral.", + "type": "object", + "required": [ + "trade_type", + "id", + "hash", + "trader", + "exchange" + ], + "properties": { + "trade_type": { + "type": "string", + "enum": [ + "PositionsConverted" + ] + }, + "id": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "block": { + "type": "integer" + }, + "confirmed_at": { + "type": "integer" + }, + "received_at": { + "type": "integer" + }, + "log_index": { + "type": "integer" + }, + "block_index": { + "type": "integer" + }, + "trader": { + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "pseudonym": { + "type": [ + "string", + "null" + ] + }, + "profile_image": { + "type": [ + "string", + "null" + ] + }, + "x_username": { + "type": [ + "string", + "null" + ] + }, + "verified_badge": { + "type": "boolean" + } + } + }, + "market_id": { + "type": "string" + }, + "index_set": { + "type": "string" + }, + "shares_amount": { + "type": "number" + }, + "exchange": { + "type": "integer" + } + } }, - "is_surebet_trade": { - "type": "boolean" + { + "title": "Cancelled", + "description": "Order cancelled on-chain.", + "type": "object", + "required": [ + "trade_type", + "id", + "hash", + "exchange" + ], + "properties": { + "trade_type": { + "type": "string", + "enum": [ + "Cancelled" + ] + }, + "id": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "block": { + "type": "integer" + }, + "confirmed_at": { + "type": "integer" + }, + "received_at": { + "type": "integer" + }, + "log_index": { + "type": "integer" + }, + "block_index": { + "type": "integer" + }, + "order_hash": { + "type": "string" + }, + "question": { + "type": [ + "string", + "null" + ] + }, + "image_url": { + "type": [ + "string", + "null" + ] + }, + "slug": { + "type": [ + "string", + "null" + ] + }, + "event_slug": { + "type": [ + "string", + "null" + ] + }, + "exchange": { + "type": "integer" + } + } }, - "surebet_price_sum": { - "type": [ - "number", - "null" - ] + { + "title": "Oracle Lifecycle Event", + "description": "Market lifecycle events: Initialization, Proposal, Dispute, Settled, Resolution, ConditionResolution, Reset, Flag, Unflag, Pause, Unpause, ManualResolution, NegRiskOutcomeReported.", + "type": "object", + "required": [ + "trade_type", + "id", + "hash", + "oracle_contract", + "condition_id" + ], + "properties": { + "trade_type": { + "type": "string", + "enum": [ + "Initialization", + "Proposal", + "Dispute", + "Settled", + "Resolution", + "ConditionResolution", + "Reset", + "Flag", + "Unflag", + "Pause", + "Unpause", + "ManualResolution", + "NegRiskOutcomeReported" + ] + }, + "id": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "block": { + "type": "integer" + }, + "confirmed_at": { + "type": "integer" + }, + "received_at": { + "type": "integer" + }, + "log_index": { + "type": "integer" + }, + "block_index": { + "type": "integer" + }, + "oracle_contract": { + "type": "string" + }, + "condition_id": { + "type": "string" + }, + "question": { + "type": [ + "string", + "null" + ] + }, + "image_url": { + "type": [ + "string", + "null" + ] + }, + "slug": { + "type": [ + "string", + "null" + ] + }, + "event_slug": { + "type": [ + "string", + "null" + ] + }, + "assertion_id": { + "type": [ + "string", + "null" + ] + }, + "proposer": { + "type": [ + "string", + "null" + ] + }, + "disputer": { + "type": [ + "string", + "null" + ] + }, + "proposed_outcome": { + "type": [ + "string", + "null" + ] + }, + "settled_price": { + "type": [ + "integer", + "null" + ] + }, + "disputed": { + "type": [ + "boolean", + "null" + ] + }, + "settlement_resolution": { + "type": [ + "boolean", + "null" + ] + }, + "bond": { + "type": [ + "string", + "null" + ] + }, + "expiration_time": { + "type": [ + "integer", + "null" + ] + }, + "creator": { + "type": [ + "string", + "null" + ] + }, + "reward_token": { + "type": [ + "string", + "null" + ] + }, + "reward": { + "type": [ + "string", + "null" + ] + }, + "proposal_bond": { + "type": [ + "string", + "null" + ] + } + } }, - "is_bot": { - "type": "boolean" + { + "title": "RegisterToken", + "description": "YES/NO token pair registered for a condition.", + "type": "object", + "required": [ + "trade_type", + "id", + "hash", + "condition_id", + "exchange" + ], + "properties": { + "trade_type": { + "type": "string", + "enum": [ + "RegisterToken" + ] + }, + "id": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "block": { + "type": "integer" + }, + "confirmed_at": { + "type": "integer" + }, + "received_at": { + "type": "integer" + }, + "log_index": { + "type": "integer" + }, + "block_index": { + "type": "integer" + }, + "condition_id": { + "type": "string" + }, + "token0": { + "type": "string" + }, + "token1": { + "type": "string" + }, + "question": { + "type": [ + "string", + "null" + ] + }, + "image_url": { + "type": [ + "string", + "null" + ] + }, + "slug": { + "type": [ + "string", + "null" + ] + }, + "event_slug": { + "type": [ + "string", + "null" + ] + }, + "exchange": { + "type": "integer" + } + } }, - "bot_reason": { - "type": [ - "string", - "null" - ] + { + "title": "Approval", + "description": "ERC-1155 setApprovalForAll — operator approved/revoked.", + "type": "object", + "required": [ + "trade_type", + "id", + "hash", + "trader", + "exchange" + ], + "properties": { + "trade_type": { + "type": "string", + "enum": [ + "Approval" + ] + }, + "id": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "block": { + "type": "integer" + }, + "confirmed_at": { + "type": "integer" + }, + "received_at": { + "type": "integer" + }, + "log_index": { + "type": "integer" + }, + "block_index": { + "type": "integer" + }, + "trader": { + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "pseudonym": { + "type": [ + "string", + "null" + ] + }, + "profile_image": { + "type": [ + "string", + "null" + ] + }, + "x_username": { + "type": [ + "string", + "null" + ] + }, + "verified_badge": { + "type": "boolean" + } + } + }, + "operator": { + "type": "string" + }, + "approved": { + "type": "boolean" + }, + "question": { + "type": [ + "string", + "null" + ] + }, + "image_url": { + "type": [ + "string", + "null" + ] + }, + "slug": { + "type": [ + "string", + "null" + ] + }, + "event_slug": { + "type": [ + "string", + "null" + ] + }, + "exchange": { + "type": "integer" + } + } } + ], + "discriminator": { + "propertyName": "trade_type" } }, "AssetPricesSubscribeMessage": { @@ -1704,10 +2611,7 @@ "usd_volume", "fees", "txns", - "unique_traders", - "historical_confirmed_at", - "latest_confirmed_at", - "latest_block" + "unique_traders" ], "properties": { "condition_id": { @@ -1751,20 +2655,6 @@ "unique_traders": { "type": "integer", "format": "int64" - }, - "historical_confirmed_at": { - "type": "integer", - "format": "int64", - "description": "Earliest trade timestamp in window (Unix seconds)" - }, - "latest_confirmed_at": { - "type": "integer", - "format": "int64", - "description": "Latest trade timestamp in window (Unix seconds)" - }, - "latest_block": { - "type": "integer", - "format": "int64" } } }, @@ -1826,10 +2716,7 @@ "usd_volume", "fees", "txns", - "unique_traders", - "historical_confirmed_at", - "latest_confirmed_at", - "latest_block" + "unique_traders" ], "properties": { "event_slug": { @@ -1870,18 +2757,6 @@ "unique_traders": { "type": "integer", "format": "int64" - }, - "historical_confirmed_at": { - "type": "integer", - "format": "int64" - }, - "latest_confirmed_at": { - "type": "integer", - "format": "int64" - }, - "latest_block": { - "type": "integer", - "format": "int64" } } }, @@ -2600,7 +3475,7 @@ }, "TraderPositionUpdateEvent": { "type": "object", - "description": "Server-pushed event: full position snapshot for a tracked trader. Envelope type: \"trader_position_update\". Pushed whenever a position's PnL changes in the database.", + "description": "Server-pushed event: full position snapshot for a tracked trader. Envelope type: \"trader_position_update\". Pushed whenever a position's PnL changes.", "required": [ "trader" ], @@ -3271,172 +4146,45 @@ } } }, - "WalletTrackingSubscribeMessage": { + "WebhookDeliveryEnvelope": { "type": "object", - "description": "Subscribe to wallet trade alerts. wallet_addresses is required.", + "description": "Outer envelope for every webhook HTTP POST delivery. The `data` field contains the event-specific payload. Delivery headers sent with every POST: `X-Webhook-ID` (subscription UUID), `X-Delivery-ID` (this attempt's UUID), `X-Event-Type` (event name string, e.g. `trader_first_trade`), `X-Attempt` (attempt number, 1-indexed). When the webhook has a secret configured, `X-Webhook-Signature: sha256=` is also included — compute HMAC-SHA256 over the raw request body using your secret to verify.", "required": [ - "action", - "wallet_addresses" + "id", + "event", + "data", + "timestamp", + "webhook_id", + "attempt" ], "properties": { - "action": { + "id": { "type": "string", - "enum": [ - "subscribe" - ] - }, - "wallet_addresses": { - "type": "array", - "items": { - "type": "string" - }, - "description": "EVM wallet addresses to track", - "minItems": 1 - } - } - }, - "WalletTrackingSubscribeResponse": { - "type": "object", - "description": "Server acknowledgement for a wallet tracking subscription", - "required": [ - "subscribed_count", - "current_user_wallets", - "total_wallets" - ], - "properties": { - "subscribed_count": { - "type": "integer", - "format": "uint64", - "description": "Number of wallets successfully subscribed" - }, - "invalid_addresses": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Addresses rejected (invalid format)" - }, - "current_user_wallets": { - "type": "array", - "items": { - "type": "string" - }, - "description": "All wallet addresses currently tracked by this user" - }, - "total_wallets": { - "type": "integer", - "format": "uint64", - "description": "Total wallet count for this user" - } - } - }, - "PredictionMarketMetadata": { - "type": "object", - "description": "Market metadata enrichment attached to wallet tracking alerts", - "properties": { - "slug": { - "type": [ - "string", - "null" - ], - "description": "Market slug" - }, - "question": { - "type": [ - "string", - "null" - ], - "description": "Market question text" - }, - "outcome": { - "type": [ - "string", - "null" - ], - "description": "Outcome name (e.g. \"Yes\")" + "format": "uuid", + "description": "UUID of this specific delivery attempt (matches X-Delivery-ID header)" }, - "outcome_index": { - "type": [ - "integer", - "null" - ] - }, - "image_url": { - "type": [ - "string", - "null" - ] - } - } - }, - "WalletTrackingAlertEvent": { - "type": "object", - "description": "Server-pushed event: a trade executed by a tracked wallet. Envelope type: \"wallet_tracking_alert\".", - "required": [ - "is_buy", - "trader", - "position_id", - "usd_amount", - "shares_amount", - "price", - "confirmed_at" - ], - "properties": { - "is_buy": { - "type": "boolean", - "description": "True = buy, false = sell" - }, - "trader": { + "event": { "type": "string", - "description": "Trader EVM wallet address (lowercase)" - }, - "condition_id": { - "type": [ - "string", - "null" - ], - "description": "64-char hex condition ID" + "description": "Event name (e.g. `trader_first_trade`). On test deliveries the suffix `_test` is appended." }, - "position_id": { - "type": "string", - "description": "ERC-1155 outcome token ID (decimal string)" + "data": { + "type": "object", + "description": "Event-specific payload — schema varies by event type; see the individual callback definitions" }, - "usd_amount": { - "type": "string", - "description": "USD value of the trade (decimal string, 6dp)" + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix timestamp in milliseconds when this delivery was created" }, - "shares_amount": { + "webhook_id": { "type": "string", - "description": "Number of shares traded (decimal string, 6dp)" - }, - "price": { - "type": "number", - "minimum": 0.0, - "maximum": 1.0, - "description": "Trade price (0–1)" + "format": "uuid", + "description": "UUID of the webhook subscription that fired (matches X-Webhook-ID header)" }, - "probability": { - "type": [ - "number", - "null" - ], - "description": "Implied probability (0–1)" - }, - "metadata": { - "oneOf": [ - { - "$ref": "#/components/schemas/PredictionMarketMetadata" - }, - { - "type": "null" - } - ], - "description": "Market metadata — null when enrichment is unavailable" - }, - "confirmed_at": { + "attempt": { "type": "integer", - "format": "int64", - "description": "Unix seconds" + "minimum": 1, + "description": "Delivery attempt number. 1 = first attempt; increments on each retry." } } }, diff --git a/package.json b/package.json index 904edd8..9b2d2c9 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "generate:webhooks": "openapi-typescript openapi/webhooks.json -o src/generated/webhooks.ts", "generate:ws": "bun run scripts/generate-ws-types.ts", "link": "bun link", - "pack": "bun run build && bun pack" + "pack": "bun run build && bun pm pack" }, "devDependencies": { "@types/bun": "latest", diff --git a/scripts/check-routes.ts b/scripts/check-routes.ts index 92b20a0..072f95f 100644 --- a/scripts/check-routes.ts +++ b/scripts/check-routes.ts @@ -4,6 +4,7 @@ import { join } from "node:path"; const NAMESPACES_DIR = join(import.meta.dirname, "../src/namespaces"); const TYPES_FILE = join(import.meta.dirname, "../src/types/index.ts"); const WS_TYPES_FILE = join(import.meta.dirname, "../src/types/ws.ts"); +const WS_ALERTS_FILE = join(import.meta.dirname, "../src/ws-alerts.ts"); interface SpecConfig { specPath: string; @@ -138,6 +139,12 @@ async function getSdkWsRooms(): Promise> { rooms.add(match[1]); } } + try { + const alertsContent = await readFile(WS_ALERTS_FILE, "utf-8"); + if (/class\s+StructAlertsWebSocket\b/.test(alertsContent)) { + rooms.add("ws_alerts"); + } + } catch {} return rooms; } diff --git a/src/generated/ws.ts b/src/generated/ws.ts index fa6b219..5b8ac10 100644 --- a/src/generated/ws.ts +++ b/src/generated/ws.ts @@ -59,7 +59,7 @@ export interface components { /** @description Restrict to these aggregation windows. */ timeframes?: ("1m" | "5m" | "30m" | "1h" | "6h" | "1d" | "24h" | "7d" | "30d")[]; }; - /** @description Subscribe to the trades stream. At least one filter field must be non-empty. */ + /** @description Subscribe to the trades stream. No filters = subscribe to all trades. */ TradesStreamSubscribeMessage: { /** @enum {string} */ action: "subscribe" | "unsubscribe_all"; @@ -71,8 +71,17 @@ export interface components { event_slugs?: string[]; /** @description ERC-1155 outcome token IDs (decimal or hex strings) */ position_ids?: string[]; - /** @description Only receive trades of these types. Empty array = all types. */ - trade_types?: ("OrderFilled" | "Redemption" | "Merge" | "Split" | "Cancelled" | "PositionsConverted" | "OrdersMatched")[]; + /** @description Trader wallet addresses (lowercase 0x-prefixed) */ + traders?: string[]; + /** @description Only receive events of these types. Empty array = all types. */ + trade_types?: ("OrderFilled" | "OrdersMatched" | "Redemption" | "Merge" | "Split" | "Cancelled" | "PositionsConverted" | "Initialization" | "Proposal" | "Dispute" | "Settled" | "Resolution" | "ConditionResolution" | "Reset" | "Flag" | "Unflag" | "Pause" | "Unpause" | "ManualResolution" | "NegRiskOutcomeReported" | "RegisterToken" | "Approval")[]; + /** + * @description Trade status filter: "confirmed" (default) = on-chain only, "pending" = mempool only, "all" = both + * @enum {string} + */ + status?: "confirmed" | "pending" | "all"; + /** @description Explicitly subscribe to all trades. Also implicitly true when no filters are provided. */ + subscribe_all?: boolean; }; /** @description Server acknowledgement for a trades stream subscription */ TradesStreamSubscribeResponse: { @@ -80,71 +89,272 @@ export interface components { market_slugs?: string[]; event_slugs?: string[]; position_ids?: string[]; + traders?: string[]; trade_types?: string[]; - /** @description Filter values that were rejected (invalid format or unknown trade type) */ + /** @enum {string} */ + status?: "confirmed" | "pending" | "all"; + subscribe_all?: boolean; + /** @description Filter values that were rejected (invalid format or unknown type) */ rejected?: string[]; }; - /** @description Server-pushed event: a matched trade on a subscribed market/position/event/slug. Envelope type: "trade_stream_update". */ + /** + * @description Server-pushed event. Discriminated by `trade_type` — each variant only includes relevant fields. + * + * Envelope: `{"type": "trade_stream_update", "room_id": "polymarket_trades", "status": "confirmed"|"pending", "data": {...}}` + * + * **Pending trades:** `block`, `confirmed_at`, `log_index`, `block_index` are absent. `received_at` (milliseconds) is included instead. For OrderFilled/OrdersMatched, `order_hash`, `taker`, `fee`, `fee_shares`, `fee_pct` are also absent. + */ TradeStreamEvent: { - /** @description Trade ID */ + /** @enum {string} */ + trade_type: "OrderFilled" | "OrdersMatched"; id: string; - /** @description Transaction hash (hex) */ hash: string; - /** Format: uint64 */ - chain_id?: number; - /** Format: uint64 */ - block: number; - /** - * Format: uint64 - * @description Unix seconds - */ - confirmed_at: number; - /** Format: uint64 */ + /** @description Absent for pending trades */ + block?: number; + /** @description Unix seconds. Absent for pending trades */ + confirmed_at?: number; + /** @description Unix milliseconds. Present for pending trades only */ + received_at?: number; + /** @description Absent for pending trades */ log_index?: number; - /** Format: uint64 */ + /** @description Absent for pending trades */ block_index?: number; - /** @description Order hash (hex) */ + /** @description Absent for pending trades */ order_hash?: string; - /** @description Limit-order maker wallet address */ - trader: string; - /** @description Order taker wallet address */ - taker: string; - /** @description "Buy" or "Sell" (null for non-trade operations like Redemption, Merge, Split) */ - side?: string | null; - /** @description 64-char hex condition ID */ + trader: { + address?: string; + name?: string | null; + pseudonym?: string | null; + profile_image?: string | null; + x_username?: string | null; + verified_badge?: boolean; + }; + /** @description Absent for pending trades */ + taker?: string; + /** @enum {string} */ + side?: "Buy" | "Sell"; condition_id?: string | null; - /** @description ERC-1155 outcome token ID (decimal string) */ - position_id: string; - /** @description Outcome name (e.g. "Yes") */ + position_id?: string; outcome?: string | null; - /** @description 0 = Yes, 1 = No */ outcome_index?: number | null; question?: string | null; - /** @description Market slug */ + image_url?: string | null; slug?: string | null; event_slug?: string | null; - /** @description USD value of the trade (decimal string) */ - usd_amount: string; - /** @description Number of shares traded (decimal string) */ - shares_amount: string; - /** @description Trade price (0–1) */ - price: number; - /** @description Implied probability (0–1) */ + usd_amount?: number; + shares_amount?: number; + price?: number; probability?: number | null; - /** @description Protocol fee paid (decimal string) */ - fee: string; - /** @description Exchange identifier */ - exchange?: string; - /** @description "OrderFilled", "Redemption", "Merge", "Split", "Cancelled", "PositionsConverted", "OrdersMatched" */ - trade_type?: string; - /** @description Resolved winning outcome index */ + /** @description Absent for pending trades */ + fee?: number; + /** @description Absent for pending trades */ + fee_shares?: number; + /** @description Absent for pending trades */ + fee_pct?: number; + exchange: number; + } | { + /** @enum {string} */ + trade_type: "Redemption"; + id: string; + hash: string; + block?: number; + confirmed_at?: number; + received_at?: number; + log_index?: number; + block_index?: number; + trader: { + address?: string; + name?: string | null; + pseudonym?: string | null; + profile_image?: string | null; + x_username?: string | null; + verified_badge?: boolean; + }; + condition_id?: string | null; + outcome?: string | null; + outcome_index?: number | null; + question?: string | null; + image_url?: string | null; + slug?: string | null; + event_slug?: string | null; + usd_amount?: number; winning_outcome_index?: number | null; - is_known_surebet?: boolean; - is_coordinated?: boolean; - is_surebet_trade?: boolean; - surebet_price_sum?: number | null; - is_bot?: boolean; - bot_reason?: string | null; + position_details?: { + position_id?: string; + outcome_index?: number; + amount?: string; + }[]; + exchange: number; + } | { + /** @enum {string} */ + trade_type: "Merge"; + id: string; + hash: string; + block?: number; + confirmed_at?: number; + received_at?: number; + log_index?: number; + block_index?: number; + trader: { + address?: string; + name?: string | null; + pseudonym?: string | null; + profile_image?: string | null; + x_username?: string | null; + verified_badge?: boolean; + }; + condition_id?: string | null; + question?: string | null; + image_url?: string | null; + slug?: string | null; + event_slug?: string | null; + usd_amount?: number; + position_details?: { + position_id?: string; + outcome_index?: number; + amount?: string; + }[]; + exchange: number; + } | { + /** @enum {string} */ + trade_type: "Split"; + id: string; + hash: string; + block?: number; + confirmed_at?: number; + received_at?: number; + log_index?: number; + block_index?: number; + trader: { + address?: string; + name?: string | null; + pseudonym?: string | null; + profile_image?: string | null; + x_username?: string | null; + verified_badge?: boolean; + }; + condition_id?: string | null; + question?: string | null; + image_url?: string | null; + slug?: string | null; + event_slug?: string | null; + usd_amount?: number; + position_details?: { + position_id?: string; + outcome_index?: number; + amount?: string; + }[]; + exchange: number; + } | { + /** @enum {string} */ + trade_type: "PositionsConverted"; + id: string; + hash: string; + block?: number; + confirmed_at?: number; + received_at?: number; + log_index?: number; + block_index?: number; + trader: { + address?: string; + name?: string | null; + pseudonym?: string | null; + profile_image?: string | null; + x_username?: string | null; + verified_badge?: boolean; + }; + market_id?: string; + index_set?: string; + shares_amount?: number; + exchange: number; + } | { + /** @enum {string} */ + trade_type: "Cancelled"; + id: string; + hash: string; + block?: number; + confirmed_at?: number; + received_at?: number; + log_index?: number; + block_index?: number; + order_hash?: string; + question?: string | null; + image_url?: string | null; + slug?: string | null; + event_slug?: string | null; + exchange: number; + } | { + /** @enum {string} */ + trade_type: "Initialization" | "Proposal" | "Dispute" | "Settled" | "Resolution" | "ConditionResolution" | "Reset" | "Flag" | "Unflag" | "Pause" | "Unpause" | "ManualResolution" | "NegRiskOutcomeReported"; + id: string; + hash: string; + block?: number; + confirmed_at?: number; + received_at?: number; + log_index?: number; + block_index?: number; + oracle_contract: string; + condition_id: string; + question?: string | null; + image_url?: string | null; + slug?: string | null; + event_slug?: string | null; + assertion_id?: string | null; + proposer?: string | null; + disputer?: string | null; + proposed_outcome?: string | null; + settled_price?: number | null; + disputed?: boolean | null; + settlement_resolution?: boolean | null; + bond?: string | null; + expiration_time?: number | null; + creator?: string | null; + reward_token?: string | null; + reward?: string | null; + proposal_bond?: string | null; + } | { + /** @enum {string} */ + trade_type: "RegisterToken"; + id: string; + hash: string; + block?: number; + confirmed_at?: number; + received_at?: number; + log_index?: number; + block_index?: number; + condition_id: string; + token0?: string; + token1?: string; + question?: string | null; + image_url?: string | null; + slug?: string | null; + event_slug?: string | null; + exchange: number; + } | { + /** @enum {string} */ + trade_type: "Approval"; + id: string; + hash: string; + block?: number; + confirmed_at?: number; + received_at?: number; + log_index?: number; + block_index?: number; + trader: { + address?: string; + name?: string | null; + pseudonym?: string | null; + profile_image?: string | null; + x_username?: string | null; + verified_badge?: boolean; + }; + operator?: string; + approved?: boolean; + question?: string | null; + image_url?: string | null; + slug?: string | null; + event_slug?: string | null; + exchange: number; }; /** @description Subscribe to the asset prices stream. Empty asset_symbols = all assets. */ AssetPricesSubscribeMessage: { @@ -262,18 +472,6 @@ export interface components { txns: number; /** Format: int64 */ unique_traders: number; - /** - * Format: int64 - * @description Earliest trade timestamp in window (Unix seconds) - */ - historical_confirmed_at: number; - /** - * Format: int64 - * @description Latest trade timestamp in window (Unix seconds) - */ - latest_confirmed_at: number; - /** Format: int64 */ - latest_block: number; }; /** @description Subscribe to the event metrics stream. event_slugs is required and must be non-empty. */ EventMetricsSubscribeMessage: { @@ -305,12 +503,6 @@ export interface components { txns: number; /** Format: int64 */ unique_traders: number; - /** Format: int64 */ - historical_confirmed_at: number; - /** Format: int64 */ - latest_confirmed_at: number; - /** Format: int64 */ - latest_block: number; }; /** @description Subscribe to the position metrics stream. position_ids is required and must be non-empty. */ PositionMetricsSubscribeMessage: { @@ -543,7 +735,7 @@ export interface components { rejected?: string[]; error?: string | null; }; - /** @description Server-pushed event: full position snapshot for a tracked trader. Envelope type: "trader_position_update". Pushed whenever a position's PnL changes in the database. */ + /** @description Server-pushed event: full position snapshot for a tracked trader. Envelope type: "trader_position_update". Pushed whenever a position's PnL changes. */ TraderPositionUpdateEvent: { /** @description Trader EVM wallet address */ trader: string; @@ -775,66 +967,29 @@ export interface components { /** @description Unix timestamp in milliseconds */ timestamp_ms?: number; }; - /** @description Subscribe to wallet trade alerts. wallet_addresses is required. */ - WalletTrackingSubscribeMessage: { - /** @enum {string} */ - action: "subscribe"; - /** @description EVM wallet addresses to track */ - wallet_addresses: string[]; - }; - /** @description Server acknowledgement for a wallet tracking subscription */ - WalletTrackingSubscribeResponse: { + /** @description Outer envelope for every webhook HTTP POST delivery. The `data` field contains the event-specific payload. Delivery headers sent with every POST: `X-Webhook-ID` (subscription UUID), `X-Delivery-ID` (this attempt's UUID), `X-Event-Type` (event name string, e.g. `trader_first_trade`), `X-Attempt` (attempt number, 1-indexed). When the webhook has a secret configured, `X-Webhook-Signature: sha256=` is also included — compute HMAC-SHA256 over the raw request body using your secret to verify. */ + WebhookDeliveryEnvelope: { /** - * Format: uint64 - * @description Number of wallets successfully subscribed + * Format: uuid + * @description UUID of this specific delivery attempt (matches X-Delivery-ID header) */ - subscribed_count: number; - /** @description Addresses rejected (invalid format) */ - invalid_addresses?: string[]; - /** @description All wallet addresses currently tracked by this user */ - current_user_wallets: string[]; + id: string; + /** @description Event name (e.g. `trader_first_trade`). On test deliveries the suffix `_test` is appended. */ + event: string; + /** @description Event-specific payload — schema varies by event type; see the individual callback definitions */ + data: Record; /** - * Format: uint64 - * @description Total wallet count for this user + * Format: int64 + * @description Unix timestamp in milliseconds when this delivery was created */ - total_wallets: number; - }; - /** @description Market metadata enrichment attached to wallet tracking alerts */ - PredictionMarketMetadata: { - /** @description Market slug */ - slug?: string | null; - /** @description Market question text */ - question?: string | null; - /** @description Outcome name (e.g. "Yes") */ - outcome?: string | null; - outcome_index?: number | null; - image_url?: string | null; - }; - /** @description Server-pushed event: a trade executed by a tracked wallet. Envelope type: "wallet_tracking_alert". */ - WalletTrackingAlertEvent: { - /** @description True = buy, false = sell */ - is_buy: boolean; - /** @description Trader EVM wallet address (lowercase) */ - trader: string; - /** @description 64-char hex condition ID */ - condition_id?: string | null; - /** @description ERC-1155 outcome token ID (decimal string) */ - position_id: string; - /** @description USD value of the trade (decimal string, 6dp) */ - usd_amount: string; - /** @description Number of shares traded (decimal string, 6dp) */ - shares_amount: string; - /** @description Trade price (0–1) */ - price: number; - /** @description Implied probability (0–1) */ - probability?: number | null; - /** @description Market metadata — null when enrichment is unavailable */ - metadata?: components["schemas"]["PredictionMarketMetadata"] | null; + timestamp: number; /** - * Format: int64 - * @description Unix seconds + * Format: uuid + * @description UUID of the webhook subscription that fired (matches X-Webhook-ID header) */ - confirmed_at: number; + webhook_id: string; + /** @description Delivery attempt number. 1 = first attempt; increments on each retry. */ + attempt: number; }; /** @description Payload delivered when a tracked trader executes their first-ever trade on Polymarket */ FirstTradePayload: { diff --git a/src/types/index.ts b/src/types/index.ts index e1cd7f7..24b74fb 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -482,9 +482,6 @@ export type { ClobRewardsSubscribeFilters, ClobRewardsUpdateEvent, ClobRewardsSubscribeResponse, - WalletTrackingSubscribeFilters, - WalletTrackingSubscribeResponse, - WalletTrackingAlertEvent, WsAlertSubscribedResponse, WsAlertUnsubscribedResponse, WsAlertErrorResponse, @@ -495,7 +492,6 @@ export type { WsAlertSubscribeMap, WsAlertEventDataMap, WsAlertEventName, - WsPredictionMarketMetadata, TradeStreamEvent, AssetPriceTickEvent, AssetPriceWindowUpdateEvent, diff --git a/src/types/ws.ts b/src/types/ws.ts index 24d9e49..5042da6 100644 --- a/src/types/ws.ts +++ b/src/types/ws.ts @@ -22,8 +22,7 @@ export type WsRoomId = | "polymarket_trader_positions" | "polymarket_accounts" | "polymarket_order_book" - | "polymarket_clob_rewards" - | "polymarket_wallet_tracking"; + | "polymarket_clob_rewards"; export type WsFiltersOptionalRoom = "polymarket_asset_prices" | "polymarket_clob_rewards"; export type WsFiltersRequiredRoom = Exclude; @@ -40,7 +39,6 @@ export type AccountsSubscribeFilters = Pick; export type TraderPositionsSubscribeFilters = Omit; export type ClobRewardsSubscribeFilters = Omit; -export type WalletTrackingSubscribeFilters = Omit; export type TradeStreamEvent = WsSchemas["TradeStreamEvent"]; export type AssetPriceTickEvent = WsSchemas["AssetPriceTickEvent"]; @@ -61,8 +59,6 @@ export type TraderPositionUpdateEvent = WsSchemas["TraderPositionUpdateEvent"]; export type TraderPositionsSubscribeResponse = WsSchemas["TraderPositionsSubscribeResponse"]; export type ClobRewardsUpdateEvent = WsSchemas["ClobRewardsUpdateEvent"]; export type ClobRewardsSubscribeResponse = WsSchemas["ClobRewardsSubscribeResponse"]; -export type WalletTrackingSubscribeResponse = WsSchemas["WalletTrackingSubscribeResponse"]; -export type WalletTrackingAlertEvent = WsSchemas["WalletTrackingAlertEvent"]; export type WsAlertSubscribeMessage = WsSchemas["WsAlertSubscribeMessage"]; export type WsAlertUnsubscribeMessage = WsSchemas["WsAlertUnsubscribeMessage"]; export type WsAlertEventPayload = WsSchemas["WsAlertEventPayload"]; @@ -70,7 +66,6 @@ export type WsAlertSubscribedResponse = WsSchemas["WsAlertSubscribedResponse"]; export type WsAlertUnsubscribedResponse = WsSchemas["WsAlertUnsubscribedResponse"]; export type WsAlertErrorResponse = WsSchemas["WsAlertErrorResponse"]; export type WsAlertEventType = WsSchemas["WsAlertEventType"]; -export type WsPredictionMarketMetadata = WsSchemas["PredictionMarketMetadata"]; export type { WsAlertSubscribeMap, WsAlertEventDataMap, WsAlertEventName }; export type TradesStreamSubscribeResponse = WsSchemas["TradesStreamSubscribeResponse"]; @@ -100,7 +95,6 @@ export interface WebSocketEventMap { order_book_update: OrderBookUpdateEvent; trader_position_update: TraderPositionUpdateEvent; clob_rewards_update: ClobRewardsUpdateEvent; - wallet_tracking_alert: WalletTrackingAlertEvent; connected: void; disconnected: { code: number; reason: string }; reconnecting: { attempt: number }; @@ -119,7 +113,6 @@ export interface WsSubscriptionMap { polymarket_accounts: AccountsSubscribeFilters; polymarket_order_book: OrderBookSubscribeFilters; polymarket_clob_rewards: ClobRewardsSubscribeFilters; - polymarket_wallet_tracking: WalletTrackingSubscribeFilters; } export interface WsSubscribeResponseMap { @@ -134,7 +127,6 @@ export interface WsSubscribeResponseMap { polymarket_accounts: AccountsSubscribeResponse; polymarket_order_book: OrderBookSubscribeResponse; polymarket_clob_rewards: ClobRewardsSubscribeResponse; - polymarket_wallet_tracking: WalletTrackingSubscribeResponse; } export type AlertsWebSocketEventMap = { diff --git a/src/ws-alerts.ts b/src/ws-alerts.ts index 7cb93cb..2cb7d13 100644 --- a/src/ws-alerts.ts +++ b/src/ws-alerts.ts @@ -31,7 +31,7 @@ export class StructAlertsWebSocket { constructor(config: StructWebSocketConfig) { this.subscribeTimeout = config.subscribeTimeout ?? DEFAULT_SUBSCRIBE_TIMEOUT_MS; const base = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, ""); - const url = `${base}/v1/ws/alerts?api-key=${encodeURIComponent(config.apiKey)}`; + const url = `${base}/ws/alerts?api-key=${encodeURIComponent(config.apiKey)}`; this.transport = new WebSocketTransport( url, From da569e5fdec86b6e2ac9f336017c6f29b764109e Mon Sep 17 00:00:00 2001 From: elliotdotsol Date: Sun, 12 Apr 2026 01:10:22 +0700 Subject: [PATCH 11/12] feat: websockets --- .github/workflows/ci.yml | 24 + .github/workflows/publish.yml | 4 + README.md | 43 +- openapi/polymarket.json | 2 +- openapi/ws-alerts.json | 9663 +++++++++++++++++++++++++++++++++ openapi/ws.json | 7204 +----------------------- scripts/check-routes.ts | 105 +- scripts/fetch-specs.ts | 1 + scripts/generate-ws-types.ts | 193 +- src/generated/polymarket.ts | 2 + src/generated/ws-alerts.ts | 2602 +++++++++ src/generated/ws.ts | 2769 +--------- src/types/http.ts | 1 + src/types/index.ts | 8 +- src/types/ws-helpers.ts | 9 +- src/types/ws.ts | 38 +- src/ws-alerts.ts | 149 +- src/ws-transport.ts | 173 +- src/ws.ts | 188 +- tests/integration.test.ts | 3 +- tests/setup/fake-websocket.ts | 86 + tests/ws-alerts.test.ts | 166 + tests/ws-transport.test.ts | 178 + tests/ws.test.ts | 244 + 24 files changed, 13946 insertions(+), 9909 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 openapi/ws-alerts.json create mode 100644 src/generated/ws-alerts.ts create mode 100644 tests/setup/fake-websocket.ts create mode 100644 tests/ws-alerts.test.ts create mode 100644 tests/ws-transport.test.ts create mode 100644 tests/ws.test.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..4a511d1 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,24 @@ +name: CI + +on: + push: + pull_request: + +permissions: + contents: read + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: oven-sh/setup-bun@v2 + + - run: bun install + + - run: bun test + + - run: bun run typecheck + + - run: bun run build diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 1b52f26..fb3f367 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -17,6 +17,10 @@ jobs: - run: bun install + - run: bun test + + - run: bun run typecheck + - run: bun run build - uses: actions/setup-node@v4 diff --git a/README.md b/README.md index 5c5ead4..34747b4 100644 --- a/README.md +++ b/README.md @@ -221,30 +221,32 @@ ws.on("clob_rewards_update", (event) => { ### Alerts -Subscribe to typed alerts with per-event filter narrowing. TypeScript ensures you only use filters valid for the selected event: +Alerts use a separate client with per-event typed filters and payloads: ```typescript -await ws.subscribe("ws_alerts", { - event: "trader_whale_trade", +import { StructAlertsWebSocket } from "@structbuild/sdk"; + +const alerts = new StructAlertsWebSocket({ apiKey: "your-api-key" }); +await alerts.connect(); + +await alerts.subscribe("trader_whale_trade", { wallet_addresses: ["0xd91..."], min_usd_value: 10000, }); -await ws.subscribe("ws_alerts", { - event: "probability_spike", +await alerts.subscribe("probability_spike", { spike_direction: "up", min_probability_change_pct: 5, }); -ws.on("ws_alert", (payload) => { - if (payload.event === "trader_whale_trade") { - payload.data.trader; - payload.data.amount_usd; - } - if (payload.event === "probability_spike") { - payload.data.spike_direction; - payload.data.spike_pct; - } +alerts.on("trader_whale_trade", (payload) => { + payload.data.trader; + payload.data.amount_usd; +}); + +alerts.on("probability_spike", (payload) => { + payload.data.spike_direction; + payload.data.spike_pct; }); ``` @@ -263,7 +265,6 @@ ws.on("ws_alert", (payload) => { | `polymarket_accounts` | `wallets` | `accounts_update`, `usdce_update`, `matic_update` | | `polymarket_order_book` | `asset_ids` | `order_book_update` | | `polymarket_clob_rewards` | `condition_ids?`, `subscribe_all?` | `clob_rewards_update` | -| `ws_alerts` | per-event typed filters | `ws_alert` | ### Lifecycle events @@ -271,6 +272,9 @@ ws.on("ws_alert", (payload) => { ws.on("connected", () => {}); ws.on("disconnected", ({ code, reason }) => {}); ws.on("reconnecting", ({ attempt }) => {}); +ws.on("reconnect_failed", (err) => {}); +ws.on("auth_failed", (err) => {}); +ws.on("warning", (warning) => {}); ws.on("error", (err) => {}); ``` @@ -303,6 +307,15 @@ const ws = new StructWebSocket({ The `pk_jwt_*` key is safe to hardcode in frontend bundles — it is useless without a valid JWT from your configured auth provider. +If your JWT can rotate while a socket stays alive, prefer `getJwt` so reconnects always rebuild the URL with a fresh token: + +```typescript +const ws = new StructWebSocket({ + apiKey: "pk_jwt_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4", + getJwt: () => userAccessToken, +}); +``` + ## Pagination Use the `paginate` helper to iterate through all results: diff --git a/openapi/polymarket.json b/openapi/polymarket.json index 6552b14..4117f78 100644 --- a/openapi/polymarket.json +++ b/openapi/polymarket.json @@ -1 +1 @@ -{"openapi":"3.1.0","info":{"title":"Polymarket API","description":"RESTful API for querying Polymarket prediction markets data including events, markets, traders, holders, and real-time metrics","license":{"name":""},"version":"1.0.0"},"servers":[{"url":"https://api.struct.to/v1","description":"Production"}],"paths":{"/polymarket/asset-history":{"get":{"tags":["Assets"],"summary":"Get Asset Price History","description":"Returns historical price data for supported crypto assets from Polymarket API","operationId":"get_asset_history","parameters":[{"name":"asset_symbol","in":"query","description":"Asset ticker: BTC, ETH, XRP, SOL, DOGE, BNB, HYPE","required":true,"schema":{"type":"string"},"example":"BTC"},{"name":"variant","in":"query","description":"Time window: 5m, 15m, 1h, 4h, 1d","required":true,"schema":{"type":"string"},"example":"1h"},{"name":"from","in":"query","description":"Start timestamp in seconds (Unix epoch, inclusive)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp in seconds (Unix epoch, inclusive)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"limit","in":"query","description":"Number of results (default: 10, max: 100)","required":false,"schema":{"type":"integer","format":"int64"},"example":10},{"name":"pagination_key","in":"query","description":"Cursor from previous response for keyset pagination. Pass the pagination_key from the previous page to fetch the next page.","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AssetPriceHistoryRow"}}}}},"400":{"description":"Bad request - missing or invalid parameters"},"500":{"description":"Internal server error"}}}},"/polymarket/events":{"get":{"tags":["Events"],"summary":"Get events","description":"Retrieve a paginated list of events with filtering, sorting, and optional nested tags/markets","operationId":"get_events","parameters":[{"name":"id","in":"query","description":"Filter by event ID(s) - comma-separated (max 50). Cannot be used with 'event_slugs'. Example: id=99600,99601,99583","required":false,"schema":{"type":"string"}},{"name":"event_slugs","in":"query","description":"Filter by event slug(s) - comma-separated (max 50). Cannot be used with 'id'. Example: event_slugs=will-trump-win,bitcoin-100k","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","description":"Search in title and description (3-100 characters). Example: search=trump","required":false,"schema":{"type":"string"}},{"name":"sort_by","in":"query","description":"Sort: volume, txns, unique_traders, title, creation_date, start_date, end_date, relevance (relevance only works in search mode) (default: volume)","required":false,"schema":{"$ref":"#/components/schemas/EventSortBy"}},{"name":"sort_dir","in":"query","description":"Sort direction: asc, desc (default: desc)","required":false,"schema":{"$ref":"#/components/schemas/SortDirection"}},{"name":"timeframe","in":"query","description":"Metrics timeframe: 1m, 5m, 30m, 1h, 6h, 24h, 7d, 30d (default: 24h)","required":false,"schema":{"$ref":"#/components/schemas/MetricsTimeframe"}},{"name":"status","in":"query","description":"Filter by status: open, closed, or all (default: all)","required":false,"schema":{"$ref":"#/components/schemas/MarketStatus"}},{"name":"categories","in":"query","description":"Comma-separated category filters","required":false,"schema":{"type":"string"}},{"name":"exclude_categories","in":"query","description":"Comma-separated categories to exclude","required":false,"schema":{"type":"string"}},{"name":"tags","in":"query","description":"Filter by tag slug(s) - comma-separated (max 50). Example: tags=sports,football,crypto","required":false,"schema":{"type":"string"}},{"name":"exclude_tags","in":"query","description":"Comma-separated tag slugs to exclude","required":false,"schema":{"type":"string"}},{"name":"min_volume","in":"query","description":"Minimum volume in selected timeframe","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_volume","in":"query","description":"Maximum volume in selected timeframe","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_txns","in":"query","description":"Minimum transactions in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"max_txns","in":"query","description":"Maximum transactions in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"min_unique_traders","in":"query","description":"Minimum unique traders in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"max_unique_traders","in":"query","description":"Maximum unique traders in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"include_tags","in":"query","description":"Include tags array (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_markets","in":"query","description":"Include markets array with outcomes (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_metrics","in":"query","description":"Include metrics object with all timeframes (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key","required":false,"schema":{"type":"string"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of Polymarket events with nested tags, markets, and series. Response includes `pagination: { has_more, pagination_key }` for cursor-based pagination.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PolymarketEvent"}}}}},"400":{"description":"Bad request - validation error (search length, array limits, conflicting params)"}}}},"/polymarket/events/chart":{"get":{"tags":["Events"],"summary":"Get event chart","description":"Retrieve price data over time for up to 4 markets with highest YES outcome (outcome_index 0) prices in an event. Perfect for rendering multi-line charts showing price movement across top markets. TradingView-style: resolution parameter determines both candle size and implicit lookback period.","operationId":"get_event_chart","parameters":[{"name":"event_slug","in":"query","description":"Event slug (required)","required":true,"schema":{"type":"string"}},{"name":"condition_ids","in":"query","description":"Comma-separated condition IDs to include (max 4, optional)","required":false,"schema":{"type":"string"}},{"name":"market_slugs","in":"query","description":"Comma-separated market slugs to include (max 4, optional). Use either condition_ids or market_slugs, not both","required":false,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Time interval with implicit lookback: 1H (1 hour), 6H (6 hours), 1D (1 day), 1W (1 week), 1M (30 days), ALL (all data) (required)","required":true,"schema":{"type":"string","enum":["1H","6H","1D","1W","1M","ALL"]}}],"responses":{"200":{"description":"Price data over time for up to 4 markets with highest YES odds","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventMarketChartOutcome"}}}}}}}},"/polymarket/events/metrics":{"get":{"tags":["Events"],"summary":"Get event metrics","description":"Retrieve volume, transaction, and trader metrics for an event. Supports single timeframe (e.g., '1m'), multiple timeframes (e.g., '1m,5m,1h'), or 'all' to get all available timeframes.","operationId":"get_event_metrics","parameters":[{"name":"event_slug","in":"query","description":"Event slug","required":true,"schema":{"type":"string"}},{"name":"timeframe","in":"query","description":"Timeframe: single (1m, 5m, 30m, 1h, 6h, 24h, 7d, 30d), comma-separated (1m,5m,1h), or 'all'","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Event metrics for the specified timeframe(s). Returns single object for one timeframe, array for multiple.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventMetricsResponse"}}}},"400":{"description":"Invalid timeframe"}}}},"/polymarket/events/outcomes":{"get":{"tags":["Events"],"summary":"Get event market outcomes","description":"Returns the winning outcome name for each resolved market in an event, keyed by market slug. Useful for quickly checking which outcomes won across a series.","operationId":"get_event_outcomes","parameters":[{"name":"event_slug","in":"query","description":"Event slug (required)","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Number of resolved markets per page (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key for fetching next page","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Map of market_slug → winning outcome name with pagination metadata","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}}}}},"400":{"description":"Missing event_slug parameter"}}}},"/polymarket/events/slug/{event_slug}":{"get":{"tags":["Events"],"summary":"Get event by slug","description":"Retrieve a single event by its slug with optional nested tags, markets, and metrics","operationId":"get_event_by_slug","parameters":[{"name":"event_slug","in":"path","description":"Event slug","required":true,"schema":{"type":"string"}},{"name":"include_tags","in":"query","description":"Include tags array (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_markets","in":"query","description":"Include markets array with outcomes (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_metrics","in":"query","description":"Include metrics object with all timeframes (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Event with nested tags, markets, and series","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PolymarketEvent"}}}},"404":{"description":"Event not found"}}}},"/polymarket/events/{identifier}":{"get":{"tags":["Events"],"summary":"Get event by ID or slug","description":"Retrieve a single event by its numeric ID or slug with optional nested tags, markets, and metrics","operationId":"get_event","parameters":[{"name":"identifier","in":"path","description":"Event ID or slug","required":true,"schema":{"type":"string"}},{"name":"include_tags","in":"query","description":"Include tags array (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_markets","in":"query","description":"Include markets array with outcomes (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_metrics","in":"query","description":"Include metrics object with all timeframes (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Event with nested tags, markets, and series","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PolymarketEvent"}}}},"404":{"description":"Event not found"}}}},"/polymarket/holders/markets":{"get":{"tags":["Holders"],"summary":"Get market holders","description":"Retrieve holders of a market grouped by outcome, sorted by shares held. Identify the market with either `condition_id` or `market_slug` — exactly one must be provided. Set `include_pnl=true` to include a nested holder `pnl` object.","operationId":"get_market_holders","parameters":[{"name":"condition_id","in":"query","description":"Market condition ID (0x-prefixed hex)","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (e.g. `will-trump-win`)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"min_shares","in":"query","description":"Minimum shares held (decimal string)","required":false,"schema":{"type":"string"}},{"name":"max_shares","in":"query","description":"Maximum shares held (decimal string)","required":false,"schema":{"type":"string"}},{"name":"include_pnl","in":"query","description":"Include nested holder PnL data (default: false, +1 credit)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Market holders grouped by outcome (sorted by shares DESC). Holder `pnl` is included only when `include_pnl=true`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarketHoldersResponse"}}}},"404":{"description":"Market not found"}}}},"/polymarket/holders/markets/history":{"get":{"tags":["Holders"],"summary":"Get market holders history","description":"Retrieve historical holder count snapshots for a market over a time range. Identify the market with either `condition_id` or `market_slug` — exactly one must be provided.","operationId":"get_market_holders_history","parameters":[{"name":"condition_id","in":"query","description":"Market condition ID (0x-prefixed hex)","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (e.g. `will-trump-win`)","required":false,"schema":{"type":"string"}},{"name":"hours","in":"query","description":"Time range in hours (default: 24, max: 336 = 14 days)","required":false,"schema":{"type":"number","format":"double"}}],"responses":{"200":{"description":"Market holder count history with automatic granularity (1m/5m/15m/1h/6h buckets)","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/HolderHistoryCandle"}}}}},"404":{"description":"Market not found"}}}},"/polymarket/holders/positions/{position_id}":{"get":{"tags":["Holders"],"summary":"Get position holders","description":"Retrieve holders of a specific position (ERC1155 token), sorted by shares held. Set `include_pnl=true` to include nested holder PnL. Uses cursor-based pagination for efficient traversal.","operationId":"get_position_holders","parameters":[{"name":"position_id","in":"path","description":"Position ID (ERC1155 token ID)","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key","required":false,"schema":{"type":"string"}},{"name":"min_shares","in":"query","description":"Minimum shares held (decimal string)","required":false,"schema":{"type":"string"}},{"name":"max_shares","in":"query","description":"Maximum shares held (decimal string)","required":false,"schema":{"type":"string"}},{"name":"include_pnl","in":"query","description":"Include nested holder PnL data (default: false, +1 credit)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Position holders (sorted by shares DESC). Holder `pnl` is included only when `include_pnl=true`. Response includes `pagination: { has_more, pagination_key }` for cursor-based pagination.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PositionHoldersResponse"}}}},"404":{"description":"Position not found"}}}},"/polymarket/holders/positions/{position_id}/history":{"get":{"tags":["Holders"],"summary":"Get position holders history","description":"Retrieve historical holder count snapshots for a position over a time range","operationId":"get_position_holders_history","parameters":[{"name":"position_id","in":"path","description":"Position ID (ERC1155 token ID)","required":true,"schema":{"type":"string"}},{"name":"hours","in":"query","description":"Time range in hours (default: 24, max: 336 = 14 days)","required":false,"schema":{"type":"number","format":"double"}}],"responses":{"200":{"description":"Position holder count history with automatic granularity (1m/5m/15m/1h/6h buckets)","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/HolderHistoryCandle"}}}}},"404":{"description":"Position not found"}}}},"/polymarket/market":{"get":{"tags":["Market"],"summary":"Get markets","description":"Retrieve a paginated list of markets with filtering, sorting, and optional nested tags/events/metrics","operationId":"list_markets","parameters":[{"name":"condition_ids","in":"query","description":"Filter by condition ID(s) - comma-separated (max 50)","required":false,"schema":{"type":"string"}},{"name":"question_ids","in":"query","description":"Filter by question ID(s) - comma-separated (max 50)","required":false,"schema":{"type":"string"}},{"name":"market_ids","in":"query","description":"Filter by market ID(s) - comma-separated (max 50)","required":false,"schema":{"type":"string"}},{"name":"market_slugs","in":"query","description":"Filter by market slug(s) - comma-separated (max 50)","required":false,"schema":{"type":"string"}},{"name":"event_slugs","in":"query","description":"Filter by event slug(s) - comma-separated (max 50)","required":false,"schema":{"type":"string"}},{"name":"position_ids","in":"query","description":"Filter by position ID(s) - comma-separated (max 50)","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","description":"Search in title (3-100 characters)","required":false,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Filter by status: open, closed, or all (default: all)","required":false,"schema":{"$ref":"#/components/schemas/MarketStatus"}},{"name":"sort_by","in":"query","description":"Sort: volume, txns, unique_traders, liquidity, holders, total_daily_rate, end_time, start_time, created_time, relevance","required":false,"schema":{"$ref":"#/components/schemas/MarketSortBy"}},{"name":"sort_dir","in":"query","description":"Sort direction: asc, desc (default: desc)","required":false,"schema":{"$ref":"#/components/schemas/SortDirection"}},{"name":"timeframe","in":"query","description":"Metrics timeframe: 1m, 5m, 30m, 1h, 6h, 24h, 7d, 30d (default: 24h)","required":false,"schema":{"$ref":"#/components/schemas/MetricsTimeframe"}},{"name":"min_volume","in":"query","description":"Minimum total volume USD","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_volume","in":"query","description":"Maximum total volume USD","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_liquidity","in":"query","description":"Minimum liquidity USD","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_liquidity","in":"query","description":"Maximum liquidity USD","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_txns","in":"query","description":"Minimum transactions in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"max_txns","in":"query","description":"Maximum transactions in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"min_unique_traders","in":"query","description":"Minimum unique traders in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"max_unique_traders","in":"query","description":"Maximum unique traders in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"min_holders","in":"query","description":"Minimum total holders","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"max_holders","in":"query","description":"Maximum total holders","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"categories","in":"query","description":"Comma-separated category filters (max 50)","required":false,"schema":{"type":"string"}},{"name":"exclude_categories","in":"query","description":"Comma-separated categories to exclude","required":false,"schema":{"type":"string"}},{"name":"tags","in":"query","description":"Filter by tag(s) - comma-separated (max 50)","required":false,"schema":{"type":"string"}},{"name":"exclude_tags","in":"query","description":"Comma-separated tags to exclude","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Filter markets with end_time >= start_time (Unix timestamp)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"end_time","in":"query","description":"Filter markets with end_time <= end_time (Unix timestamp)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"include_tags","in":"query","description":"Include tags array (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_event","in":"query","description":"Include event object (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_metrics","in":"query","description":"Include all timeframe metrics (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key","required":false,"schema":{"type":"string"}},{"name":"has_rewards","in":"query","description":"Only return markets that have CLOB rewards (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of markets with metadata, outcomes, tags, event, and metrics. Response includes `pagination: { has_more, pagination_key }` for cursor-based pagination.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MarketResponse"}}}}},"400":{"description":"Bad request - validation error (search length, array limits, conflicting params)"}}}},"/polymarket/market/bonds":{"get":{"tags":["Bonds"],"summary":"Get bonds","description":"Retrieve a list of bond markets sorted by yield, filtered by probability and time to expiry","operationId":"get_bonds","parameters":[{"name":"min_probability","in":"query","description":"Minimum probability threshold (default: 0.85)","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_hours","in":"query","description":"Maximum hours until market end","required":false,"schema":{"type":"number","format":"double"}},{"name":"limit","in":"query","description":"Number of results (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor for pagination: end_date (unix epoch) of the last item from the previous page","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"List of bond markets sorted by yield","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BondMarket"}}}}}}}},"/polymarket/market/candlestick":{"get":{"tags":["Market"],"summary":"Get market candlesticks by condition_id","description":"Retrieve OHLCV candlestick data for a market by its condition_id","operationId":"get_market_candlestick","parameters":[{"name":"condition_id","in":"query","description":"Market condition ID (required)","required":true,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Candle interval: 1, 5, 15, 30, 60, 240, D, 1D","required":true,"schema":{"$ref":"#/components/schemas/CandlestickResolution"}},{"name":"count_back","in":"query","description":"Number of candles (max: 2500)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"from","in":"query","description":"Start timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"OHLCV candlestick data","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PredictionCandlestickBar"}}}}}}}},"/polymarket/market/chart":{"get":{"tags":["Market"],"summary":"Get market chart","description":"Retrieve price data over time for up to 4 position outcomes in a market condition. TradingView-style: resolution parameter determines both candle size and implicit lookback period. Auto-selects the 4 most active outcomes if position_ids not specified.","operationId":"get_chart","parameters":[{"name":"condition_id","in":"query","description":"Market condition ID or market_slug (one required)","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (alternative to condition_id)","required":false,"schema":{"type":"string"}},{"name":"position_ids","in":"query","description":"Comma-separated list of position IDs (max 4, optional). Auto-selected if not provided","required":false,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Time interval with implicit lookback: 1H (1 hour), 6H (6 hours), 1D (1 day), 1W (1 week), 1M (30 days), ALL (all data) (required)","required":true,"schema":{"type":"string","enum":["1H","6H","1D","1W","1M","ALL"]}}],"responses":{"200":{"description":"Price data over time for up to 4 market outcomes","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PositionChartOutcome"}}}}}}}},"/polymarket/market/metrics":{"get":{"tags":["Market"],"summary":"Get market metrics","description":"Retrieve volume, transaction, and trader metrics for a market. Supports single timeframe (e.g., '1m'), multiple timeframes (e.g., '1m,5m,1h'), or 'all' to get all available timeframes.","operationId":"get_market_metrics","parameters":[{"name":"condition_id","in":"query","description":"Market condition ID","required":true,"schema":{"type":"string"}},{"name":"timeframe","in":"query","description":"Timeframe: single (1m, 5m, 30m, 1h, 6h, 24h, 7d, 30d), comma-separated (1m,5m,1h), or 'all'","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Market metrics for the specified timeframe(s). Returns single object for one timeframe, array for multiple.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConditionMetricsResponse"}}}},"400":{"description":"Invalid timeframe"}}}},"/polymarket/market/position/candlestick":{"get":{"tags":["Market"],"summary":"Get position candlesticks by position_id","description":"Retrieve OHLCV candlestick data for a specific position by its position_id","operationId":"get_position_candlestick","parameters":[{"name":"position_id","in":"query","description":"Position/token ID (required)","required":true,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Candle interval: 1, 5, 15, 30, 60, 240, D, 1D","required":true,"schema":{"$ref":"#/components/schemas/CandlestickResolution"}},{"name":"count_back","in":"query","description":"Number of candles (max: 2500)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"from","in":"query","description":"Start timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"OHLCV candlestick data","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PredictionCandlestickBar"}}}}}}}},"/polymarket/market/position/metrics":{"get":{"tags":["Market"],"summary":"Get position metrics","description":"Retrieve volume, transaction, and trader metrics for a specific position. Supports single timeframe (e.g., '1m'), multiple timeframes (e.g., '1m,5m,1h'), or 'all' to get all available timeframes.","operationId":"get_position_metrics","parameters":[{"name":"position_id","in":"query","description":"Position/token ID","required":true,"schema":{"type":"string"}},{"name":"timeframe","in":"query","description":"Timeframe: single (1m, 5m, 30m, 1h, 6h, 24h, 7d, 30d), comma-separated (1m,5m,1h), or 'all'","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Position metrics for the specified timeframe(s). Returns single object for one timeframe, array for multiple.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PositionMetricsResponse"}}}},"400":{"description":"Invalid timeframe"}}}},"/polymarket/market/position/volume-chart":{"get":{"tags":["Market"],"summary":"Get position volume chart","description":"Retrieve volume over time for a specific position with buy/sell breakdown","operationId":"get_position_volume_chart","parameters":[{"name":"position_id","in":"query","description":"Position/token ID (required)","required":true,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Time interval: 1, 5, 15, 30, 60, 240, D, 1D (default: 60)","required":false,"schema":{"$ref":"#/components/schemas/CandlestickResolution"}},{"name":"count_back","in":"query","description":"Number of data points (max: 2500)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"from","in":"query","description":"Start timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Volume with buy/sell breakdown over time","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PositionVolumeDataPoint"}}}}}}}},"/polymarket/market/price-jumps":{"get":{"tags":["Market"],"summary":"Detect price jumps","description":"Scan candles for significant price movements. Returns jumps with from/to timestamps in milliseconds, directly usable as trades API time range parameters to identify traders who traded before or during the movement.","operationId":"get_price_jumps","parameters":[{"name":"condition_id","in":"query","description":"Market condition ID (one of condition_id or market_slug required)","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (resolved to condition_id)","required":false,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Candle resolution in minutes: 1, 5, 15, 30, 60, 240 (default: 15)","required":false,"schema":{"type":"string"}},{"name":"min_change_pct","in":"query","description":"Minimum relative percent change to qualify as a jump (default: 10.0)","required":false,"schema":{"type":"number","format":"double"}},{"name":"lookback","in":"query","description":"Number of candles to scan back from now (default: 1440, max: 2500)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"offset","in":"query","description":"Offset in candles from now — window is [now - (lookback + offset) * resolution, now - offset * resolution] (default: 0)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Price jumps sorted by timestamp descending","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PriceJump"}}}}}}}},"/polymarket/market/slug/{market_slug}":{"get":{"tags":["Market"],"summary":"Get market by slug","description":"Retrieve a single market by its slug with optional nested tags, event, and metrics","operationId":"get_market_by_slug","parameters":[{"name":"market_slug","in":"path","description":"Market slug (e.g. `will-trump-win`)","required":true,"schema":{"type":"string"}},{"name":"include_tags","in":"query","description":"Include tags array (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_event","in":"query","description":"Include event object (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_metrics","in":"query","description":"Include all timeframe metrics (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Market with metadata, outcomes, tags, event, and metrics","content":{"application/json":{"schema":{"type":"object","description":"Formatted market response with structured metrics, tags, outcomes, and event","required":["condition_id","status"],"properties":{"condition_id":{"type":"string"},"id":{"type":["string","null"]},"market_slug":{"type":["string","null"]},"question":{"type":["string","null"]},"title":{"type":["string","null"]},"description":{"type":["string","null"]},"image_url":{"type":["string","null"]},"oracle":{"type":["string","null"]},"status":{"type":"string"},"created_time":{"type":["integer","null"],"format":"int64"},"start_time":{"type":["integer","null"],"format":"int64"},"game_start_time":{"type":["integer","null"],"format":"int64"},"closed_time":{"type":["integer","null"],"format":"int64"},"end_time":{"type":["integer","null"],"format":"int64"},"accepting_orders":{"type":["boolean","null"]},"uma_resolution_status":{"type":["string","null"]},"is_neg_risk":{"type":["boolean","null"]},"market_maker_address":{"type":["string","null"]},"creator":{"type":["string","null"]},"category":{"type":["string","null"]},"volume_usd":{"type":["number","null"],"format":"double"},"liquidity_usd":{"type":["number","null"],"format":"double"},"highest_probability":{"type":["number","null"],"format":"double"},"total_holders":{"type":["integer","null"],"format":"int64"},"total_daily_rate":{"type":["number","null"],"format":"double"},"winning_outcome":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/MarketOutcome"}]},"outcomes":{"type":"array","items":{"$ref":"#/components/schemas/MarketOutcome"}},"clob_rewards":{"type":"array","items":{"$ref":"#/components/schemas/ClobReward"}},"tags":{"type":"array","items":{"type":"string"}},"event_slug":{"type":["string","null"]},"resolution_source":{"type":["string","null"]},"metrics":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/SimpleTimeframeMetrics"},"propertyNames":{"type":"string"}},"relevance_score":{"type":["number","null"],"format":"double"}}}}}},"404":{"description":"Market not found"}}}},"/polymarket/market/trades":{"get":{"tags":["Market"],"summary":"Get market trades","description":"Retrieve trades for one or more markets, with filtering by trader, side, price, amount, and time range","operationId":"get_market_trades","parameters":[{"name":"condition_ids","in":"query","description":"Comma-separated condition IDs (max 20)","required":false,"schema":{"type":"string"}},{"name":"slugs","in":"query","description":"Comma-separated market slugs","required":false,"schema":{"type":"string"}},{"name":"position_ids","in":"query","description":"Comma-separated position IDs","required":false,"schema":{"type":"string"}},{"name":"traders","in":"query","description":"Comma-separated trader addresses (max 25)","required":false,"schema":{"type":"string"}},{"name":"side","in":"query","description":"Trade side: 0 (Buy), 1 (Sell)","required":false,"schema":{"$ref":"#/components/schemas/TradeSide"}},{"name":"outcome","in":"query","description":"Outcome name filter (e.g. Yes, No)","required":false,"schema":{"type":"string"}},{"name":"outcome_index","in":"query","description":"Outcome index: 0 (Yes), 1 (No)","required":false,"schema":{"$ref":"#/components/schemas/OutcomeIndex"}},{"name":"trade_types","in":"query","description":"Comma-separated trade types: OrderFilled, Redemption, Merge, Split, Cancelled, PositionsConverted, OrdersMatched","required":false,"schema":{"type":"string"}},{"name":"min_usd_amount","in":"query","description":"Min USD amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_usd_amount","in":"query","description":"Max USD amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_shares_amount","in":"query","description":"Min shares amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_shares_amount","in":"query","description":"Max shares amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_price","in":"query","description":"Min price (0.0-1.0)","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_price","in":"query","description":"Max price (0.0-1.0)","required":false,"schema":{"type":"number","format":"double"}},{"name":"from","in":"query","description":"Start timestamp (ms)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (ms)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"all","in":"query","description":"Return all-time trades, not just last 30 days (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Results per page (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32","minimum":0}},{"name":"offset","in":"query","description":"Pagination offset (number of results to skip). Takes precedence over pagination_key.","required":false,"schema":{"type":"integer","format":"int32","minimum":0}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key obtained from previous response's pagination.pagination_key","required":false,"schema":{"type":"string"}},{"name":"sort_desc","in":"query","description":"Sort newest first (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Prediction trades matching filters","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TradeEvent"}}}}}}}},"/polymarket/market/volume-chart":{"get":{"tags":["Market"],"summary":"Get market volume chart","description":"Retrieve volume breakdown by YES/NO outcome over time for a prediction market","operationId":"get_market_volume_chart","parameters":[{"name":"condition_id","in":"query","description":"Market condition ID (or use market_slug)","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (alternative to condition_id)","required":false,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Time interval: 1, 5, 15, 30, 60, 240, D, 1D (default: 60)","required":false,"schema":{"$ref":"#/components/schemas/CandlestickResolution"}},{"name":"count_back","in":"query","description":"Number of data points (max: 2500)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"from","in":"query","description":"Start timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Volume breakdown by YES/NO over time","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MarketVolumeDataPoint"}}}}}}}},"/polymarket/market/{condition_id}":{"get":{"tags":["Market"],"summary":"Get market by condition ID","description":"Retrieve a single market by its condition ID with optional nested tags, event, and metrics","operationId":"get_market","parameters":[{"name":"condition_id","in":"path","description":"Market condition ID (0x-prefixed hex)","required":true,"schema":{"type":"string"}},{"name":"include_tags","in":"query","description":"Include tags array (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_event","in":"query","description":"Include event object (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_metrics","in":"query","description":"Include all timeframe metrics (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Market with metadata, outcomes, tags, event, and metrics","content":{"application/json":{"schema":{"type":"object","description":"Formatted market response with structured metrics, tags, outcomes, and event","required":["condition_id","status"],"properties":{"condition_id":{"type":"string"},"id":{"type":["string","null"]},"market_slug":{"type":["string","null"]},"question":{"type":["string","null"]},"title":{"type":["string","null"]},"description":{"type":["string","null"]},"image_url":{"type":["string","null"]},"oracle":{"type":["string","null"]},"status":{"type":"string"},"created_time":{"type":["integer","null"],"format":"int64"},"start_time":{"type":["integer","null"],"format":"int64"},"game_start_time":{"type":["integer","null"],"format":"int64"},"closed_time":{"type":["integer","null"],"format":"int64"},"end_time":{"type":["integer","null"],"format":"int64"},"accepting_orders":{"type":["boolean","null"]},"uma_resolution_status":{"type":["string","null"]},"is_neg_risk":{"type":["boolean","null"]},"market_maker_address":{"type":["string","null"]},"creator":{"type":["string","null"]},"category":{"type":["string","null"]},"volume_usd":{"type":["number","null"],"format":"double"},"liquidity_usd":{"type":["number","null"],"format":"double"},"highest_probability":{"type":["number","null"],"format":"double"},"total_holders":{"type":["integer","null"],"format":"int64"},"total_daily_rate":{"type":["number","null"],"format":"double"},"winning_outcome":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/MarketOutcome"}]},"outcomes":{"type":"array","items":{"$ref":"#/components/schemas/MarketOutcome"}},"clob_rewards":{"type":"array","items":{"$ref":"#/components/schemas/ClobReward"}},"tags":{"type":"array","items":{"type":"string"}},"event_slug":{"type":["string","null"]},"resolution_source":{"type":["string","null"]},"metrics":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/SimpleTimeframeMetrics"},"propertyNames":{"type":"string"}},"relevance_score":{"type":["number","null"],"format":"double"}}}}}},"404":{"description":"Market not found"}}}},"/polymarket/order-book":{"get":{"tags":["Order Book"],"summary":"Get order book","description":"Returns the latest CLOB orderbook snapshot for a position, including derived metrics (best bid/ask, mid price, spread, liquidity depth). Data is sourced from the real-time Polymarket WebSocket feed. `bids` and `asks` are arrays of `{\"p\": price, \"s\": size}` objects, sorted best-first.","operationId":"get_order_book","parameters":[{"name":"position_id","in":"query","description":"Token ID (position ID) to query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Latest orderbook snapshot. ts is Unix milliseconds.","content":{"application/json":{"schema":{"type":"object","required":["ts","position_id","condition_id","bids","asks","hash"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"bids":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"asks":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"hash":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}}}}},"400":{"description":"Missing or invalid parameters"}}}},"/polymarket/order-book/history":{"get":{"tags":["Order Book"],"summary":"Get order book history","description":"Paginated history of raw CLOB orderbook snapshots including full bids/asks levels and derived metrics. Default limit 20, max 200. `bids` and `asks` are arrays of `{\"p\": price, \"s\": size}` objects, sorted best-first.","operationId":"get_order_book_history","parameters":[{"name":"position_id","in":"query","description":"Token ID (required if condition_id / market_slug not set)","required":false,"schema":{"type":"string"}},{"name":"condition_id","in":"query","description":"Condition ID — returns history for all positions in this market","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (alternative to condition_id)","required":false,"schema":{"type":"string"}},{"name":"from","in":"query","description":"Start timestamp (Unix milliseconds, inclusive)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (Unix milliseconds, inclusive)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"min_spread","in":"query","description":"Only return snapshots with spread >= this value","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_spread","in":"query","description":"Only return snapshots with spread <= this value","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_liquidity","in":"query","description":"Only return snapshots where total liquidity (bid + ask) >= this value","required":false,"schema":{"type":"number","format":"double"}},{"name":"limit","in":"query","description":"Number of results (default: 20, max: 200)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"pagination_key","in":"query","description":"Cursor from previous response's pagination.pagination_key","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Orderbook snapshot rows, newest first. ts is Unix milliseconds.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","required":["ts","position_id","condition_id","bids","asks","hash"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"bids":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"asks":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"hash":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}}}}}},"400":{"description":"Missing or invalid parameters"}}}},"/polymarket/order-book/market":{"get":{"tags":["Order Book"],"summary":"Get order books for a market","description":"Returns the latest orderbook snapshot for every position (outcome) in a market. Accepts condition_id or market_slug. `bids` and `asks` are arrays of `{\"p\": price, \"s\": size}` objects, sorted best-first.","operationId":"get_market_order_book","parameters":[{"name":"condition_id","in":"query","description":"Condition ID of the market","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (alternative to condition_id)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Latest orderbook snapshot per position. ts is Unix milliseconds.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","required":["ts","position_id","condition_id","bids","asks","hash"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"bids":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"asks":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"hash":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}}}}}},"400":{"description":"Missing or invalid parameters"}}}},"/polymarket/order-book/spread":{"get":{"tags":["Order Book"],"summary":"Get spread history","description":"Lightweight time series of derived orderbook metrics (best bid/ask, mid price, spread, liquidity depth) without raw bids/asks — ideal for charting. Default limit 20, max 200.","operationId":"get_spread_history","parameters":[{"name":"position_id","in":"query","description":"Token ID (required if condition_id / market_slug not set)","required":false,"schema":{"type":"string"}},{"name":"condition_id","in":"query","description":"Condition ID — returns spread history for all positions in this market","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (alternative to condition_id)","required":false,"schema":{"type":"string"}},{"name":"from","in":"query","description":"Start timestamp (Unix milliseconds, inclusive)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (Unix milliseconds, inclusive)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"min_spread","in":"query","description":"Only return rows with spread >= this value","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_spread","in":"query","description":"Only return rows with spread <= this value","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_liquidity","in":"query","description":"Only return rows where total liquidity (bid + ask) >= this value","required":false,"schema":{"type":"number","format":"double"}},{"name":"limit","in":"query","description":"Number of results (default: 100, max: 1000)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"pagination_key","in":"query","description":"Cursor from previous response's pagination.pagination_key","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Spread time series rows, newest first. ts is Unix milliseconds.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","description":"Lightweight row — derived metrics only, no bids/asks JSONB.","required":["ts","position_id","condition_id"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}}}}}},"400":{"description":"Missing or invalid parameters"}}}},"/polymarket/search":{"get":{"tags":["Search"],"summary":"Search events, markets, and traders","description":"Search across markets, events, and traders. Use `type` to limit which categories are searched. Trader search supports wallet address lookup or name search. Results for each category are independently paginated. Only requested categories are included in the response.","operationId":"search","parameters":[{"name":"q","in":"query","description":"Search query (min 2 characters). Prefix with 0x for exact wallet address lookup.","required":true,"schema":{"type":"string"}},{"name":"type","in":"query","description":"Comma-separated categories to search: events, markets, traders (default: all three, 1 credit per type). Example: type=markets,traders","required":false,"schema":{"type":"string"}},{"name":"include_pnl","in":"query","description":"Include lifetime PnL summary for each trader (default: false, +1 credit)","required":false,"schema":{"type":"boolean"}},{"name":"sort_by","in":"query","description":"Sort field applied to both events and markets (default: volume). Fields marked events-only or markets-only fall back to volume on the other category.","required":false,"schema":{"$ref":"#/components/schemas/SearchSortBy"}},{"name":"sort_dir","in":"query","description":"Sort direction (default: desc)","required":false,"schema":{"$ref":"#/components/schemas/SortDirection"}},{"name":"timeframe","in":"query","description":"Metrics timeframe used for volume/txns/unique_traders sort (default: 24h)","required":false,"schema":{"$ref":"#/components/schemas/MetricsTimeframe"}},{"name":"limit","in":"query","description":"Results limit per category (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"events_pagination_key","in":"query","description":"Cursor for the next page of events, obtained from previous response's events_pagination.pagination_key","required":false,"schema":{"type":"string"}},{"name":"markets_pagination_key","in":"query","description":"Cursor for the next page of markets, obtained from previous response's markets_pagination.pagination_key","required":false,"schema":{"type":"string"}},{"name":"traders_pagination_key","in":"query","description":"Cursor for the next page of traders, obtained from previous response's traders_pagination.pagination_key","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Search results. Only requested categories (via `type`) are included in the response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchResponse"}}}},"400":{"description":"Bad request — q is missing or shorter than 2 characters"}}}},"/polymarket/series":{"get":{"tags":["Series"],"summary":"List or get series","description":"Retrieve series. Use `id` or `series_slug` for single lookup, `series_ids` or `series_slugs` (comma-separated, max 250, mutually exclusive) for multi-lookup, or paginate with `active_only`.","operationId":"get_series_list","parameters":[{"name":"id","in":"query","description":"Single series ID for direct lookup","required":false,"schema":{"type":"string"}},{"name":"series_ids","in":"query","description":"Comma-separated series IDs (max 250). Mutually exclusive with series_slugs.","required":false,"schema":{"type":"string"}},{"name":"series_slugs","in":"query","description":"Comma-separated series slugs (max 250). Mutually exclusive with series_ids.","required":false,"schema":{"type":"string"}},{"name":"active_only","in":"query","description":"Only active series (default: true). Ignored when series_ids or series_slugs are provided.","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor for pagination: id of the last series from the previous page","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Series or list of series","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PolymarketSeries"}}}}},"400":{"description":"series_ids and series_slugs cannot both be provided"}}}},"/polymarket/series/outcomes":{"get":{"tags":["Series"],"summary":"Get series market outcomes","description":"Returns the winning outcome name for each resolved market across all events in a series, keyed by market slug. Useful for checking historical results across recurring series (e.g., btc-updown-5m).","operationId":"get_series_outcomes","parameters":[{"name":"series_slug","in":"query","description":"Series slug (required)","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Number of resolved markets per page (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key for fetching next page","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Map of market_slug → winning outcome name with pagination metadata","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}}}}},"400":{"description":"Missing series_slug parameter"}}}},"/polymarket/tags":{"get":{"tags":["Tags"],"summary":"Get tags","description":"Retrieve all available event tags/categories. Supports both cursor-based and offset-based pagination.","operationId":"get_tags","parameters":[{"name":"limit","in":"query","description":"Results limit (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"offset","in":"query","description":"Offset-based pagination (number of results to skip). Takes precedence over pagination_key.","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of all tags","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PolymarketTag"}}}}}}}},"/polymarket/tags/{identifier}":{"get":{"tags":["Tags"],"summary":"Get tag by slug","description":"Retrieve a single tag by its ID or slug","operationId":"get_tag_by_id","parameters":[{"name":"identifier","in":"path","description":"Tag ID or slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Tag details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PolymarketTag"}}}},"404":{"description":"Tag not found"}}}},"/polymarket/trader/global_pnl":{"get":{"tags":["Trader"],"summary":"Get global leaderboard","description":"Retrieve the global PnL leaderboard ranked by profit and loss. Uses cursor-based pagination for efficient traversal of large datasets.","operationId":"get_global_pnl","parameters":[{"name":"timeframe","in":"query","description":"Timeframe: 1d, 7d, 30d, lifetime (default: lifetime)","required":false,"schema":{"$ref":"#/components/schemas/PnlTimeframe"}},{"name":"sort_by","in":"query","description":"Sort: realized_pnl_usd, buys, sells, redemptions, merges, avg_hold_time, markets_traded, events_traded, markets_won, volume_usd, fees, best_trade (default: realized_pnl_usd)","required":false,"schema":{"$ref":"#/components/schemas/GlobalPnlSortBy"}},{"name":"sort_direction","in":"query","description":"Sort direction: asc, desc (default: desc)","required":false,"schema":{"$ref":"#/components/schemas/SortDirection"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 200)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Global PnL leaderboard with trader stats. Response includes `pagination: { has_more, pagination_key }` for cursor-based pagination.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GlobalPnlTrader"}}}}}}}},"/polymarket/trader/pnl/{address}":{"get":{"tags":["Trader"],"summary":"Get trader PnL summary","description":"Retrieve a trader's overall profit and loss summary","operationId":"get_trader_pnl","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"timeframe","in":"query","description":"Timeframe: 1d, 7d, 30d, lifetime (default: lifetime)","required":false,"schema":{"$ref":"#/components/schemas/PnlTimeframe"}}],"responses":{"200":{"description":"Trader's global PnL summary","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TraderPnlSummary"}}}}}}},"/polymarket/trader/pnl/{address}/calendar":{"get":{"tags":["Trader"],"summary":"Get trader PnL calendar","description":"Retrieve raw per-day PnL. Each entry is the realized PnL for that calendar day. Paginate backwards using the pagination key.","operationId":"get_trader_pnl_calendar","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"days","in":"query","description":"Window size in days (default: 30, max: 30)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Pagination key obtained from a previous response to fetch an earlier window","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Daily PnL entries (one per active trading day)","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PnlCandleEntry"}}}}}}}},"/polymarket/trader/pnl/{address}/candles":{"get":{"tags":["Trader"],"summary":"Get trader PnL candles","description":"Retrieve PnL candles for charting a trader's equity curve over time.","operationId":"get_trader_pnl_candles","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Candle resolution (default: 1h)","required":false,"schema":{"$ref":"#/components/schemas/PnlCandleResolution"}},{"name":"timeframe","in":"query","description":"Time range (default: lifetime)","required":false,"schema":{"$ref":"#/components/schemas/PnlCandleTimeframe"}}],"responses":{"200":{"description":"Cumulative PnL candles","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PnlCandleEntry"}}}}}}}},"/polymarket/trader/pnl/{address}/events":{"get":{"tags":["Trader"],"summary":"Get trader event PnL","description":"Retrieve event-level PnL breakdown for a trader","operationId":"get_trader_event_pnl","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"timeframe","in":"query","description":"Timeframe: 1d, 7d, 30d, lifetime (default: lifetime)","required":false,"schema":{"$ref":"#/components/schemas/PnlTimeframe"}},{"name":"sort_by","in":"query","description":"Sort: realized_pnl_usd, total_volume_usd, markets_traded, total_fees (default: realized_pnl_usd)","required":false,"schema":{"$ref":"#/components/schemas/EventPnlSortBy"}},{"name":"sort_direction","in":"query","description":"Sort direction: asc, desc (default: desc)","required":false,"schema":{"$ref":"#/components/schemas/SortDirection"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 200)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"offset","in":"query","description":"Pagination offset (number of results to skip). Takes precedence over pagination_key.","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key obtained from previous response's pagination.pagination_key","required":false,"schema":{"type":"string"}},{"name":"event_slug","in":"query","description":"Filter by event slug","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Event-level PnL entries for this trader","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TraderEventPnlEntry"}}}}}}}},"/polymarket/trader/pnl/{address}/markets":{"get":{"tags":["Trader"],"summary":"Get trader market PnL","description":"Retrieve market-level PnL breakdown for a trader","operationId":"get_trader_market_pnl","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"timeframe","in":"query","description":"Timeframe: 1d, 7d, 30d, lifetime (default: lifetime)","required":false,"schema":{"$ref":"#/components/schemas/PnlTimeframe"}},{"name":"sort_by","in":"query","description":"Sort: realized_pnl_usd, buy_usd, total_buys, total_fees, outcomes_traded (default: realized_pnl_usd)","required":false,"schema":{"$ref":"#/components/schemas/MarketPnlSortBy"}},{"name":"sort_direction","in":"query","description":"Sort direction: asc, desc (default: desc)","required":false,"schema":{"$ref":"#/components/schemas/SortDirection"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 200)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"offset","in":"query","description":"Pagination offset (number of results to skip). Takes precedence over pagination_key.","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key obtained from previous response's pagination.pagination_key","required":false,"schema":{"type":"string"}},{"name":"condition_id","in":"query","description":"Filter by condition ID (or use market_slug)","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Filter by market slug (alternative to condition_id)","required":false,"schema":{"type":"string"}},{"name":"event_slug","in":"query","description":"Filter by event slug","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Market-level PnL entries for this trader","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TraderMarketPnlEntry"}}}}}}}},"/polymarket/trader/pnl/{address}/positions":{"get":{"tags":["Trader"],"summary":"Get trader position PnL","description":"Retrieve per-outcome-token lifetime PnL for a trader from polymarket_accounts. Includes open/closed state, win/loss outcome, redemption payouts, and share quantities. Filter by status and won/lost to segment portfolio views.","operationId":"get_trader_position_pnl","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Required. Filter by position status","required":true,"schema":{"type":"string","enum":["open","closed"]}},{"name":"won","in":"query","description":"Filter by outcome: true (won), false (lost), only for status=closed","required":false,"schema":{"type":"boolean"}},{"name":"search","in":"query","description":"Search by market title","required":false,"schema":{"type":"string"}},{"name":"sort_by","in":"query","description":"Sort field (default: realized_pnl_usd)","required":false,"schema":{"$ref":"#/components/schemas/PositionPnlSortBy"}},{"name":"sort_direction","in":"query","description":"Sort direction: asc, desc (default: desc)","required":false,"schema":{"$ref":"#/components/schemas/SortDirection"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 200)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"offset","in":"query","description":"Pagination offset","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"condition_id","in":"query","description":"Filter by market condition ID (or use market_slug)","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Filter by market slug (alternative to condition_id)","required":false,"schema":{"type":"string"}},{"name":"position_id","in":"query","description":"Filter by specific outcome token (position ID)","required":false,"schema":{"type":"string"}},{"name":"min_shares","in":"query","description":"Minimum shares balance to include. Status filtering already treats balances below 0.01 shares as dust.","required":false,"schema":{"type":"number","format":"double"}}],"responses":{"200":{"description":"Position-level PnL entries for this trader. Each entry is a specific outcome token with open/closed state, avg_entry_price, avg_exit_price, and redemption info.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TraderOutcomePnlEntry"}}}}}}}},"/polymarket/trader/profile/{address}":{"get":{"tags":["Trader"],"summary":"Get trader overview","description":"Retrieve a trader's profile including stats and trading history summary","operationId":"get_trader_profile","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Trader profile information with username, bio, and badges","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PolymarketUserProfile"}}}}}}},"/polymarket/trader/profiles/batch":{"get":{"tags":["Trader"],"summary":"Get multiple trader profiles","description":"Retrieve profiles for multiple traders in a single request. Returns an array of profiles.","operationId":"get_trader_profiles_batch","parameters":[{"name":"addresses","in":"query","description":"Comma-separated list of trader addresses (max: 20)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Array of trader profiles","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PolymarketUserProfile"}}}}},"400":{"description":"Invalid request (empty addresses or more than 20)"}}}},"/polymarket/trader/trades/{address}":{"get":{"tags":["Trader"],"summary":"Get trader trades","description":"Retrieve trade history for a specific trader across all markets","operationId":"get_trader_trades","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"condition_ids","in":"query","description":"Comma-separated condition IDs (max 20)","required":false,"schema":{"type":"string"}},{"name":"slugs","in":"query","description":"Comma-separated market slugs","required":false,"schema":{"type":"string"}},{"name":"position_ids","in":"query","description":"Comma-separated position IDs","required":false,"schema":{"type":"string"}},{"name":"side","in":"query","description":"Trade side: 0 (Buy), 1 (Sell)","required":false,"schema":{"$ref":"#/components/schemas/TradeSide"}},{"name":"outcome","in":"query","description":"Outcome name filter (e.g. Yes, No)","required":false,"schema":{"type":"string"}},{"name":"outcome_index","in":"query","description":"Outcome index: 0 (Yes), 1 (No)","required":false,"schema":{"$ref":"#/components/schemas/OutcomeIndex"}},{"name":"trade_types","in":"query","description":"Comma-separated trade types: OrderFilled, Redemption, Merge, Split, Cancelled, PositionsConverted, OrdersMatched","required":false,"schema":{"type":"string"}},{"name":"min_usd_amount","in":"query","description":"Min USD amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_usd_amount","in":"query","description":"Max USD amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_shares_amount","in":"query","description":"Min shares amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_shares_amount","in":"query","description":"Max shares amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_price","in":"query","description":"Min price (0.0-1.0)","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_price","in":"query","description":"Max price (0.0-1.0)","required":false,"schema":{"type":"number","format":"double"}},{"name":"from","in":"query","description":"Start timestamp (ms)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (ms)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"all","in":"query","description":"Return all-time trades, not just last 30 days (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Results per page (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32","minimum":0}},{"name":"offset","in":"query","description":"Pagination offset (number of results to skip). Takes precedence over pagination_key.","required":false,"schema":{"type":"integer","format":"int32","minimum":0}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key obtained from previous response's pagination.pagination_key","required":false,"schema":{"type":"string"}},{"name":"sort_desc","in":"query","description":"Sort newest first (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Trader's trade history with advanced filtering (same as /market/trades but filtered by trader)","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TradeEvent"}}}}}}}},"/polymarket/trader/volume-chart/{address}":{"get":{"tags":["Trader"],"summary":"Get trader volume chart","description":"Retrieve volume breakdown by buy/sell over time for a specific trader","operationId":"get_trader_volume_chart","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Time interval: 1, 5, 15, 30, 60, 240, D, 1D (default: 60)","required":false,"schema":{"$ref":"#/components/schemas/CandlestickResolution"}},{"name":"count_back","in":"query","description":"Number of data points (max: 2500)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"from","in":"query","description":"Start timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Trader volume with buy/sell breakdown over time","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TraderVolumeDataPoint"}}}}}}}}},"components":{"schemas":{"ApprovalTrade":{"type":"object","description":"Output payload for ERC1155 setApprovalForAll events.","required":["id","hash","trader","operator","approved","exchange"],"properties":{"id":{"type":"string"},"hash":{"type":"string"},"block":{"type":["integer","null"],"format":"int64","minimum":0},"confirmed_at":{"type":["integer","null"],"format":"int64","minimum":0},"received_at":{"type":["integer","null"],"format":"int64","minimum":0},"log_index":{"type":["integer","null"],"format":"int64","minimum":0},"block_index":{"type":["integer","null"],"format":"int64","minimum":0},"trader":{"$ref":"#/components/schemas/TraderInfo"},"operator":{"type":"string"},"approved":{"type":"boolean"},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"slug":{"type":["string","null"]},"event_slug":{"type":["string","null"]},"exchange":{"$ref":"#/components/schemas/PolymarketExchange"}}},"AssertionDisputedEvent":{"type":"object","description":"V3 UMA OOv3: an assertion was disputed.","required":["id","hash","oracle_contract","assertion_id","caller","disputer"],"properties":{"id":{"type":"string"},"hash":{"type":"string"},"block":{"type":["integer","null"],"format":"int64","minimum":0},"confirmed_at":{"type":["integer","null"],"format":"int64","minimum":0},"received_at":{"type":["integer","null"],"format":"int64","minimum":0},"log_index":{"type":["integer","null"],"format":"int64","minimum":0},"block_index":{"type":["integer","null"],"format":"int64","minimum":0},"oracle_contract":{"type":"string"},"assertion_id":{"type":"string"},"caller":{"type":"string"},"disputer":{"type":"string"},"condition_id":{"type":["string","null"]},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"slug":{"type":["string","null"]},"event_slug":{"type":["string","null"]}}},"AssertionMadeEvent":{"type":"object","description":"V3 UMA OOv3: a new assertion (resolution proposal) was made.","required":["id","hash","oracle_contract","assertion_id","domain_id","claim","asserter","callback_recipient","escalation_manager","caller","expiration_time","currency","bond","identifier"],"properties":{"id":{"type":"string"},"hash":{"type":"string"},"block":{"type":["integer","null"],"format":"int64","minimum":0},"confirmed_at":{"type":["integer","null"],"format":"int64","minimum":0},"received_at":{"type":["integer","null"],"format":"int64","minimum":0},"log_index":{"type":["integer","null"],"format":"int64","minimum":0},"block_index":{"type":["integer","null"],"format":"int64","minimum":0},"oracle_contract":{"type":"string"},"assertion_id":{"type":"string"},"domain_id":{"type":"string"},"claim":{"type":"string"},"asserter":{"type":"string"},"callback_recipient":{"type":"string"},"escalation_manager":{"type":"string"},"caller":{"type":"string"},"expiration_time":{"type":"integer","format":"int64","minimum":0},"currency":{"type":"string"},"bond":{"type":"string"},"identifier":{"type":"string"},"condition_id":{"type":["string","null"]},"proposed_outcome":{"type":["string","null"]},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"slug":{"type":["string","null"]},"event_slug":{"type":["string","null"]}}},"AssertionSettledEvent":{"type":"object","description":"V3 UMA OOv3: an assertion liveness period expired and was settled.","required":["id","hash","oracle_contract","assertion_id","bond_recipient","disputed","settlement_resolution","settle_caller"],"properties":{"id":{"type":"string"},"hash":{"type":"string"},"block":{"type":["integer","null"],"format":"int64","minimum":0},"confirmed_at":{"type":["integer","null"],"format":"int64","minimum":0},"received_at":{"type":["integer","null"],"format":"int64","minimum":0},"log_index":{"type":["integer","null"],"format":"int64","minimum":0},"block_index":{"type":["integer","null"],"format":"int64","minimum":0},"oracle_contract":{"type":"string"},"assertion_id":{"type":"string"},"bond_recipient":{"type":"string"},"disputed":{"type":"boolean"},"settlement_resolution":{"type":"boolean"},"settle_caller":{"type":"string"},"condition_id":{"type":["string","null"]},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"slug":{"type":["string","null"]},"event_slug":{"type":["string","null"]}}},"AssetPriceHistoryRow":{"type":"object","description":"A single asset price history record from the `asset_price_history` table.","required":["asset_symbol","asset_open_price","asset_close_price","variant","start_time","end_time"],"properties":{"asset_symbol":{"type":"string"},"asset_open_price":{"type":"number","format":"double","description":"Opening price at start_time (cast to f64 from NUMERIC in query)"},"asset_close_price":{"type":"number","format":"double","description":"Closing price at end_time (cast to f64 from NUMERIC in query)"},"price_change_percentage":{"type":["number","null"],"format":"double"},"outcome":{"type":["string","null"],"description":"Generated column: \"up\" if close > open, \"down\" if close ≤ open, null if no close yet"},"variant":{"type":"string","description":"Time window: \"5m\", \"15m\", \"1h\", \"1d\""},"start_time":{"type":"integer","format":"int64","description":"Window start timestamp (seconds since epoch)"},"end_time":{"type":"integer","format":"int64","description":"Window end timestamp (seconds since epoch)"}}},"AssetSymbol":{"type":"string","enum":["BTC","ETH","XRP","SOL","DOGE","BNB","HYPE"]},"AssetVariant":{"type":"string","enum":["5m","15m","1h","4h","1d"]},"BondMarket":{"type":"object","required":["condition_id","question","market_slug","end_time","best_outcome_index","return_pct","apy","outcomes"],"properties":{"condition_id":{"type":"string"},"title":{"type":["string","null"]},"question":{"type":"string"},"market_slug":{"type":"string"},"event_slug":{"type":["string","null"]},"image_url":{"type":["string","null"]},"end_time":{"type":"integer","format":"int64"},"best_outcome_index":{"type":"integer","format":"int32","minimum":0},"return_pct":{"type":"number","format":"double"},"apy":{"type":"number","format":"double"},"volume_24h":{"type":["number","null"],"format":"double"},"outcomes":{"type":"array","items":{"$ref":"#/components/schemas/BondOutcome"}}}},"BondOutcome":{"type":"object","required":["name","index","position_id","price"],"properties":{"name":{"type":"string"},"index":{"type":"integer","format":"int32"},"position_id":{"type":"string"},"price":{"type":"number","format":"double"}}},"CancelledTrade":{"type":"object","description":"Output payload for Cancelled orders.","required":["id","hash","exchange"],"properties":{"id":{"type":"string"},"hash":{"type":"string"},"block":{"type":["integer","null"],"format":"int64","minimum":0},"confirmed_at":{"type":["integer","null"],"format":"int64","minimum":0},"received_at":{"type":["integer","null"],"format":"int64","minimum":0},"log_index":{"type":["integer","null"],"format":"int64","minimum":0},"block_index":{"type":["integer","null"],"format":"int64","minimum":0},"order_hash":{"type":["string","null"]},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"slug":{"type":["string","null"]},"event_slug":{"type":["string","null"]},"exchange":{"$ref":"#/components/schemas/PolymarketExchange"}}},"CandlestickResolution":{"type":"string","enum":["1","5","15","30","60","240","D","1D"]},"ChartResolution":{"type":"string","enum":["1H","6H","1D","1W","1M","ALL"]},"ClobReward":{"type":"object","description":"CLOB reward (public API format)","required":["id","condition_id"],"properties":{"id":{"type":"string"},"condition_id":{"type":"string"},"asset_address":{"type":["string","null"]},"rewards_amount":{"type":["number","null"],"format":"double"},"rewards_daily_rate":{"type":["number","null"],"format":"double"},"start_date":{"type":["string","null"]},"end_date":{"type":["string","null"]},"rewards_max_spread":{"type":["number","null"],"format":"double"},"rewards_min_size":{"type":["number","null"],"format":"double"},"native_daily_rate":{"type":["number","null"],"format":"double"},"sponsored_daily_rate":{"type":["number","null"],"format":"double"},"total_daily_rate":{"type":["number","null"],"format":"double"},"sponsors_count":{"type":["integer","null"],"format":"int32"}}},"ConditionMetricsResponse":{"type":"object","description":"Response type for condition metrics query","required":["condition_id","timeframe","volume_usd","fees","txns","unique_traders"],"properties":{"condition_id":{"type":"string"},"timeframe":{"type":"string"},"volume_usd":{"type":"number","format":"double"},"fees":{"type":"number","format":"double"},"txns":{"type":"integer","format":"int32"},"unique_traders":{"type":"integer","format":"int32"}}},"ConditionOrderbookRow":{"type":"object","required":["ts","position_id","condition_id","bids","asks","hash"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"bids":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"asks":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"hash":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}},"ConditionResolutionEvent":{"type":"object","description":"CTF ConditionResolution: positions become redeemable on the Conditional Tokens contract.","required":["id","hash","oracle_contract","condition_id","oracle"],"properties":{"id":{"type":"string"},"hash":{"type":"string"},"block":{"type":["integer","null"],"format":"int64","minimum":0},"confirmed_at":{"type":["integer","null"],"format":"int64","minimum":0},"received_at":{"type":["integer","null"],"format":"int64","minimum":0},"log_index":{"type":["integer","null"],"format":"int64","minimum":0},"block_index":{"type":["integer","null"],"format":"int64","minimum":0},"oracle_contract":{"type":"string"},"condition_id":{"type":"string"},"oracle":{"type":"string"},"proposed_outcome":{"type":["string","null"]},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"slug":{"type":["string","null"]},"event_slug":{"type":["string","null"]}}},"EventMarket":{"type":"object","description":"Enriched market data for event API responses","properties":{"condition_id":{"type":"string","default":""},"id":{"type":["string","null"],"default":null},"title":{"type":["string","null"],"default":null},"question":{"type":"string","default":""},"market_slug":{"type":"string","default":""},"status":{"type":"string","default":""},"created_time":{"type":["integer","null"],"format":"int64","default":null},"end_time":{"type":["integer","null"],"format":"int64","default":null},"volume":{"type":["number","null"],"format":"double","default":null},"liquidity_usd":{"type":["number","null"],"format":"double","default":null},"volume_24hr":{"type":["number","null"],"format":"double","default":null},"image_url":{"type":["string","null"],"default":null},"market_maker_address":{"type":["string","null"],"default":null},"creator":{"type":["string","null"],"default":null},"category":{"type":["string","null"],"default":null},"accepting_orders":{"type":["boolean","null"],"default":null},"uma_resolution_status":{"type":["string","null"],"default":null},"clob_rewards":{"type":"array","items":{"$ref":"#/components/schemas/ClobReward"},"default":[]},"outcomes":{"type":"array","items":{"$ref":"#/components/schemas/EventMarketOutcome"},"default":[]},"winning_outcome":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/EventMarketOutcome"}],"default":null}}},"EventMarketChartDataPoint":{"type":"object","required":["v","t"],"properties":{"v":{"type":"number","format":"double"},"t":{"type":"integer","format":"int64","minimum":0}}},"EventMarketChartOutcome":{"type":"object","required":["condition_id","market_slug","question","title","data"],"properties":{"condition_id":{"type":"string"},"market_slug":{"type":"string"},"question":{"type":"string"},"title":{"type":"string"},"data":{"type":"array","items":{"$ref":"#/components/schemas/EventMarketChartDataPoint"}}}},"EventMarketOutcome":{"type":"object","description":"Market outcome for event API responses","required":["name"],"properties":{"name":{"type":"string"},"price":{"type":["number","null"],"format":"double"},"position_id":{"type":["string","null"]},"outcome_index":{"type":["integer","null"],"format":"int32"}}},"EventMetricsResponse":{"type":"object","description":"Response type for event metrics query","required":["event_slug","timeframe","volume_usd","fees","txns","unique_traders"],"properties":{"event_slug":{"type":"string"},"timeframe":{"type":"string"},"volume_usd":{"type":"number","format":"double"},"fees":{"type":"number","format":"double"},"txns":{"type":"integer","format":"int32"},"unique_traders":{"type":"integer","format":"int32"}}},"EventPnlSortBy":{"type":"string","enum":["realized_pnl_usd","total_volume_usd","markets_traded","total_fees","realized_pnl_pct"]},"EventSortBy":{"type":"string","enum":["volume","txns","unique_traders","title","creation_date","start_date","end_date","relevance"]},"GlobalPnlSortBy":{"type":"string","enum":["realized_pnl_usd","buys","sells","redemptions","merges","avg_hold_time","markets_traded","events_traded","markets_won","volume_usd","fees","best_trade"]},"GlobalPnlTrader":{"type":"object","description":"Individual trader entry in the global PnL leaderboard","required":["trader"],"properties":{"trader":{"$ref":"#/components/schemas/TraderInfo"},"realized_pnl_usd":{"type":["number","null"],"format":"double"},"events_traded":{"type":["integer","null"],"format":"int64"},"markets_traded":{"type":["integer","null"],"format":"int64"},"markets_won":{"type":["integer","null"],"format":"int64"},"markets_lost":{"type":["integer","null"],"format":"int64"},"market_win_rate_pct":{"type":["number","null"],"format":"double"},"total_volume_usd":{"type":["number","null"],"format":"double"},"buy_volume_usd":{"type":["number","null"],"format":"double"},"sell_volume_usd":{"type":["number","null"],"format":"double"},"redemption_volume_usd":{"type":["number","null"],"format":"double"},"merge_volume_usd":{"type":["number","null"],"format":"double"},"total_buys":{"type":["integer","null"],"format":"int64"},"total_sells":{"type":["integer","null"],"format":"int64"},"total_redemptions":{"type":["integer","null"],"format":"int64"},"total_merges":{"type":["integer","null"],"format":"int64"},"total_trades":{"type":["integer","null"],"format":"int64"},"total_fees":{"type":["number","null"],"format":"double"},"avg_pnl_per_market":{"type":["number","null"],"format":"double"},"avg_pnl_per_trade":{"type":["number","null"],"format":"double"},"avg_hold_time_seconds":{"type":["number","null"],"format":"double"},"best_trade_pnl_usd":{"type":["number","null"],"format":"double"},"best_trade_condition_id":{"type":["string","null"]},"first_trade_at":{"type":["integer","null"],"format":"int64"},"last_trade_at":{"type":["integer","null"],"format":"int64"}}},"Holder":{"type":"object","description":"Individual holder data","required":["trader","shares"],"properties":{"trader":{"$ref":"#/components/schemas/Trader","description":"Trader profile information"},"shares":{"type":"string","description":"Position shares held (raw balance as string for precision)"},"shares_usd":{"type":["string","null"],"description":"USD value of shares (shares * latest price)"},"usd_balance":{"type":["string","null"],"description":"USD balance of wallet (USDe on Polygon)"},"pnl":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/HolderPnl","description":"Holder-level PnL, included only when `include_pnl=true`"}]}}},"HolderHistoryCandle":{"type":"object","description":"Holder statistics data point (single time bucket)","required":["t"],"properties":{"t":{"type":"integer","format":"int64"},"h":{"type":["integer","null"],"format":"int64"}}},"HolderPnl":{"type":"object","description":"Holder-level PnL data, included when `include_pnl=true`","properties":{"avg_entry_price":{"type":["number","null"],"format":"double"},"total_cost_usd":{"type":["string","null"]},"unrealized_pnl_usd":{"type":["string","null"]},"realized_sell_pnl_usd":{"type":["string","null"]},"avg_exit_price":{"type":["number","null"],"format":"double"},"buy_usd":{"type":["number","null"],"format":"double"},"sell_usd":{"type":["number","null"],"format":"double"},"total_buys":{"type":["integer","null"],"format":"int64"},"total_sells":{"type":["integer","null"],"format":"int64"},"total_fees":{"type":["number","null"],"format":"double"},"first_trade_at":{"type":["integer","null"],"format":"int64"},"last_trade_at":{"type":["integer","null"],"format":"int64"}}},"MarketHoldersResponse":{"type":"object","description":"Response for market (condition_id) holders endpoint","required":["condition_id","total_holders","outcomes"],"properties":{"condition_id":{"type":"string","description":"Market condition ID"},"question":{"type":["string","null"],"description":"Market question/title"},"slug":{"type":["string","null"],"description":"Market slug"},"total_holders":{"type":"integer","format":"int64","description":"Total unique holders across all outcomes (from holder_stats)"},"outcomes":{"type":"array","items":{"$ref":"#/components/schemas/OutcomeHolders"},"description":"Holders grouped by outcome"}}},"MarketMetadataOutcome":{"type":"object","description":"Market outcome with timeframe metrics (websocket API format)","required":["token_id","outcome"],"properties":{"token_id":{"type":"string"},"outcome":{"type":"string"},"last_price":{"type":["number","null"],"format":"double"},"last_probability":{"type":["number","null"],"format":"double"},"metrics":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/OutcomeTimeframeMetrics"},"propertyNames":{"type":"string"}}}},"MarketOutcome":{"type":"object","description":"Outcome for market API responses","properties":{"name":{"type":"string","default":""},"price":{"type":["number","null"],"format":"double","default":null},"position_id":{"type":["string","null"],"default":null},"outcome_index":{"type":["integer","null"],"format":"int32","default":null}}},"MarketPnlSortBy":{"type":"string","enum":["realized_pnl_usd","buy_usd","total_buys","total_fees","outcomes_traded","realized_pnl_pct"]},"MarketResponse":{"type":"object","description":"Formatted market response with structured metrics, tags, outcomes, and event","required":["condition_id","status"],"properties":{"condition_id":{"type":"string"},"id":{"type":["string","null"]},"market_slug":{"type":["string","null"]},"question":{"type":["string","null"]},"title":{"type":["string","null"]},"description":{"type":["string","null"]},"image_url":{"type":["string","null"]},"oracle":{"type":["string","null"]},"status":{"type":"string"},"created_time":{"type":["integer","null"],"format":"int64"},"start_time":{"type":["integer","null"],"format":"int64"},"game_start_time":{"type":["integer","null"],"format":"int64"},"closed_time":{"type":["integer","null"],"format":"int64"},"end_time":{"type":["integer","null"],"format":"int64"},"accepting_orders":{"type":["boolean","null"]},"uma_resolution_status":{"type":["string","null"]},"is_neg_risk":{"type":["boolean","null"]},"market_maker_address":{"type":["string","null"]},"creator":{"type":["string","null"]},"category":{"type":["string","null"]},"volume_usd":{"type":["number","null"],"format":"double"},"liquidity_usd":{"type":["number","null"],"format":"double"},"highest_probability":{"type":["number","null"],"format":"double"},"total_holders":{"type":["integer","null"],"format":"int64"},"total_daily_rate":{"type":["number","null"],"format":"double"},"winning_outcome":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/MarketOutcome"}]},"outcomes":{"type":"array","items":{"$ref":"#/components/schemas/MarketOutcome"}},"clob_rewards":{"type":"array","items":{"$ref":"#/components/schemas/ClobReward"}},"tags":{"type":"array","items":{"type":"string"}},"event_slug":{"type":["string","null"]},"resolution_source":{"type":["string","null"]},"metrics":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/SimpleTimeframeMetrics"},"propertyNames":{"type":"string"}},"relevance_score":{"type":["number","null"],"format":"double"}}},"MarketSortBy":{"type":"string","enum":["volume","txns","unique_traders","liquidity","holders","total_daily_rate","end_time","start_time","created_time","relevance"]},"MarketStatus":{"type":"string","enum":["open","closed","all"]},"MarketVolumeChartResponse":{"type":"object","required":["volumes","has_more"],"properties":{"volumes":{"type":"array","items":{"$ref":"#/components/schemas/MarketVolumeDataPoint"}},"has_more":{"type":"boolean"}}},"MarketVolumeDataPoint":{"type":"object","required":["t","v","yv","nv","tc","ytc","ntc"],"properties":{"t":{"type":"integer","format":"int64"},"v":{"type":"number","format":"double"},"yv":{"type":"number","format":"double"},"nv":{"type":"number","format":"double"},"tc":{"type":"integer","format":"int32"},"ytc":{"type":"integer","format":"int32"},"ntc":{"type":"integer","format":"int32"}}},"MergeTrade":{"type":"object","description":"Output payload for Merge trades (burn outcome tokens → receive collateral).","required":["id","hash","trader","usd_amount","exchange"],"properties":{"id":{"type":"string"},"hash":{"type":"string"},"block":{"type":["integer","null"],"format":"int64","minimum":0},"confirmed_at":{"type":["integer","null"],"format":"int64","minimum":0},"received_at":{"type":["integer","null"],"format":"int64","minimum":0},"log_index":{"type":["integer","null"],"format":"int64","minimum":0},"block_index":{"type":["integer","null"],"format":"int64","minimum":0},"trader":{"$ref":"#/components/schemas/TraderInfo"},"condition_id":{"type":["string","null"]},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"slug":{"type":["string","null"]},"event_slug":{"type":["string","null"]},"usd_amount":{"type":"number","format":"double"},"position_details":{"type":"array","items":{"$ref":"#/components/schemas/PositionDetail"},"description":"Per-position burn amounts"},"exchange":{"$ref":"#/components/schemas/PolymarketExchange"}}},"MetricsTimeframe":{"type":"string","enum":["1m","5m","30m","1h","6h","24h","7d","30d"]},"NegRiskOutcomeReportedEvent":{"type":"object","description":"NegRisk Adapter: outcome reported for a neg-risk market question.","required":["id","hash","oracle_contract","condition_id"],"properties":{"id":{"type":"string"},"hash":{"type":"string"},"block":{"type":["integer","null"],"format":"int64","minimum":0},"confirmed_at":{"type":["integer","null"],"format":"int64","minimum":0},"received_at":{"type":["integer","null"],"format":"int64","minimum":0},"log_index":{"type":["integer","null"],"format":"int64","minimum":0},"block_index":{"type":["integer","null"],"format":"int64","minimum":0},"oracle_contract":{"type":"string"},"condition_id":{"type":"string"},"proposed_outcome":{"type":["string","null"]},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"slug":{"type":["string","null"]},"event_slug":{"type":["string","null"]}}},"OrderFilledTrade":{"type":"object","description":"Output payload for OrderFilled and OrdersMatched trades (actual buy/sell).","required":["id","hash","trader","side","position_id","usd_amount","shares_amount","price","exchange"],"properties":{"id":{"type":"string"},"hash":{"type":"string"},"block":{"type":["integer","null"],"format":"int64","minimum":0},"confirmed_at":{"type":["integer","null"],"format":"int64","minimum":0},"received_at":{"type":["integer","null"],"format":"int64","minimum":0},"log_index":{"type":["integer","null"],"format":"int64","minimum":0},"block_index":{"type":["integer","null"],"format":"int64","minimum":0},"order_hash":{"type":["string","null"]},"trader":{"$ref":"#/components/schemas/TraderInfo"},"taker":{"type":["string","null"]},"side":{"type":"string"},"condition_id":{"type":["string","null"]},"position_id":{"type":"string"},"outcome":{"type":["string","null"]},"outcome_index":{"type":["integer","null"],"format":"int32","minimum":0},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"slug":{"type":["string","null"]},"event_slug":{"type":["string","null"]},"usd_amount":{"type":"number","format":"double"},"shares_amount":{"type":"number","format":"double"},"price":{"type":"number","format":"double"},"probability":{"type":["number","null"],"format":"double"},"fee":{"type":["number","null"],"format":"double"},"fee_shares":{"type":["number","null"],"format":"double"},"fee_pct":{"type":["number","null"],"format":"double"},"exchange":{"$ref":"#/components/schemas/PolymarketExchange"}}},"OrderbookHistoryRow":{"type":"object","required":["ts","position_id","condition_id","bids","asks","hash"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"bids":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"asks":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"hash":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}},"OrderbookLevel":{"type":"object","description":"A single price level in a bids/asks array.","required":["p","s"],"properties":{"p":{"type":"string","description":"Price as a decimal string"},"s":{"type":"string","description":"Size as a decimal string"}}},"OrderbookSnapshotRow":{"type":"object","required":["ts","position_id","condition_id","bids","asks","hash"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"bids":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"asks":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"hash":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}},"OutcomeHolders":{"type":"object","description":"Holder data grouped by outcome for market-level queries","required":["outcome_index","outcome_name","position_id","total_holders","holders"],"properties":{"outcome_index":{"type":"integer","format":"int32","description":"Outcome index (0, 1, etc.)"},"outcome_name":{"type":"string","description":"Outcome name (Yes, No, etc.)"},"position_id":{"type":"string","description":"Position ID for this outcome"},"price":{"type":["number","null"],"format":"double","description":"Current price/probability"},"total_holders":{"type":"integer","format":"int64","description":"Total holders count from holder_stats"},"holders":{"type":"array","items":{"$ref":"#/components/schemas/Holder"},"description":"Top holders for this outcome"}}},"OutcomeIndex":{"type":"string","enum":["0","1"]},"OutcomeTimeframeMetrics":{"type":"object","properties":{"volume":{"type":"number","format":"double","default":0},"buy_volume":{"type":"number","format":"double","default":0},"sell_volume":{"type":"number","format":"double","default":0},"txns":{"type":"integer","format":"int32","default":0},"buys":{"type":"integer","format":"int32","default":0},"sells":{"type":"integer","format":"int32","default":0},"price_open":{"type":["number","null"],"format":"double","default":null},"price_close":{"type":["number","null"],"format":"double","default":null},"price_high":{"type":["number","null"],"format":"double","default":null},"price_low":{"type":["number","null"],"format":"double","default":null},"probability_open":{"type":["number","null"],"format":"double","default":null},"probability_close":{"type":["number","null"],"format":"double","default":null},"probability_high":{"type":["number","null"],"format":"double","default":null},"probability_low":{"type":["number","null"],"format":"double","default":null},"price_change_percent":{"type":["number","null"],"format":"double","default":null}}},"PaginationMeta":{"type":"object","description":"Pagination metadata to include in API responses","required":["has_more"],"properties":{"has_more":{"type":"boolean","description":"Whether there are more results available"},"pagination_key":{"type":["string","null"],"description":"Pagination key for the next page (if has_more is true)"}}},"PnlCandleEntry":{"type":"object","description":"A single PnL candle entry","required":["t","pnl"],"properties":{"t":{"type":"integer","format":"int64","description":"Timestamp in epoch seconds (start of bucket window)"},"pnl":{"type":"number","format":"double","description":"Realized PnL in this bucket (USD)"}}},"PnlCandleResolution":{"type":"string","enum":["1m","1h","1d"]},"PnlCandleTimeframe":{"type":"string","enum":["1d","7d","30d","lifetime"]},"PnlTimeframe":{"type":"string","enum":["1d","7d","30d","lifetime"]},"PolymarketEvent":{"type":"object","description":"A Polymarket event from the Gamma API","properties":{"id":{"type":"string","default":""},"event_slug":{"type":["string","null"],"default":null},"title":{"type":["string","null"],"default":null},"ticker":{"type":["string","null"],"default":null},"description":{"type":["string","null"],"default":null},"resolution_source":{"type":["string","null"],"default":null},"category":{"type":["string","null"],"default":null},"image_url":{"type":["string","null"],"default":null},"market_count":{"type":"integer","format":"int32","default":0},"created_time":{"type":["integer","null"],"format":"int64","default":null},"closed_time":{"type":["integer","null"],"format":"int64","default":null},"start_time":{"type":["integer","null"],"format":"int64","default":null},"end_time":{"type":["integer","null"],"format":"int64","default":null},"neg_risk":{"type":"boolean","default":false},"neg_risk_market_id":{"type":["string","null"],"default":null},"game_status":{"type":["string","null"],"default":null},"show_market_images":{"type":"boolean","default":false},"status":{"type":["string","null"],"description":"Event status: \"open\" or \"closed\"","default":null},"metrics":{"type":"object","default":{},"additionalProperties":{"$ref":"#/components/schemas/SimpleTimeframeMetrics"},"propertyNames":{"type":"string"}},"tags":{"type":"array","items":{"$ref":"#/components/schemas/PolymarketTag"},"default":[]},"markets":{"type":"array","items":{"$ref":"#/components/schemas/EventMarket"},"default":[]},"series":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PolymarketSeries"}],"default":null}}},"PolymarketExchange":{"type":"string","description":"Polymarket exchange contract types","enum":["CTFExchange","NegRiskExchange","ConditionalTokens","NegRiskAdapter","Unknown"]},"PolymarketSeries":{"type":"object","description":"A Polymarket series from the Gamma API\nSeries are parent groupings above events (e.g., \"NBA Season 2024-25\")","properties":{"id":{"type":"string","default":""},"slug":{"type":["string","null"],"default":null},"ticker":{"type":["string","null"],"default":null},"title":{"type":["string","null"],"default":null},"description":{"type":["string","null"],"default":null},"series_type":{"type":["string","null"],"default":null},"recurrence":{"type":["string","null"],"default":null},"layout":{"type":["string","null"],"default":null},"image_url":{"type":["string","null"],"default":null},"icon_url":{"type":["string","null"],"default":null},"active":{"type":"boolean","default":false},"closed":{"type":"boolean","default":false},"archived":{"type":"boolean","default":false},"featured":{"type":"boolean","default":false},"restricted":{"type":"boolean","default":false},"pyth_token_id":{"type":["string","null"],"default":null},"cg_asset_name":{"type":["string","null"],"default":null},"start_date":{"type":["integer","null"],"format":"int64","default":null},"event_count":{"type":"integer","format":"int32","default":0}}},"PolymarketTag":{"type":"object","description":"A Polymarket tag from the Gamma API","properties":{"id":{"type":"string","default":""},"label":{"type":"string","default":""},"slug":{"type":["string","null"],"default":null}}},"PolymarketUserProfile":{"type":"object","description":"Polymarket user profile (public API format)","required":["proxy_wallet","display_username_public","verified_badge","is_creator","is_mod"],"properties":{"proxy_wallet":{"type":"string"},"name":{"type":["string","null"]},"pseudonym":{"type":["string","null"]},"bio":{"type":["string","null"]},"profile_image":{"type":["string","null"]},"x_username":{"type":["string","null"]},"display_username_public":{"type":"boolean"},"verified_badge":{"type":"boolean"},"user_id":{"type":["string","null"]},"is_creator":{"type":"boolean"},"is_mod":{"type":"boolean"},"created_at":{"type":["string","null"]}}},"PositionChartDataPoint":{"type":"object","required":["v","t"],"properties":{"v":{"type":"number","format":"double"},"t":{"type":"integer","format":"int64","minimum":0}}},"PositionChartOutcome":{"type":"object","required":["position_id","name","outcome_index","data"],"properties":{"position_id":{"type":"string"},"name":{"type":"string"},"outcome_index":{"type":"integer","format":"int32"},"data":{"type":"array","items":{"$ref":"#/components/schemas/PositionChartDataPoint"}}}},"PositionDetail":{"type":"object","description":"Per-position detail for Split/Merge/Redemption trades.","required":["position_id","outcome_index","amount"],"properties":{"position_id":{"type":"string","description":"ERC1155 position ID"},"outcome_index":{"type":"integer","format":"int32","description":"Outcome index (0 = Yes, 1 = No for binary)","minimum":0},"amount":{"type":"string","description":"Amount of shares created/burned/redeemed for this position"}}},"PositionHoldersResponse":{"type":"object","description":"Response for position (position_id) holders endpoint","required":["position_id","total_holders","holders"],"properties":{"position_id":{"type":"string","description":"Position ID (ERC1155 token ID)"},"condition_id":{"type":["string","null"],"description":"Condition ID this position belongs to"},"outcome_name":{"type":["string","null"],"description":"Outcome name"},"outcome_index":{"type":["integer","null"],"format":"int32","description":"Outcome index"},"price":{"type":["number","null"],"format":"double","description":"Current price"},"total_holders":{"type":"integer","format":"int64","description":"Total holders count from holder_stats"},"holders":{"type":"array","items":{"$ref":"#/components/schemas/Holder"},"description":"Top holders"}}},"PositionMetricsResponse":{"type":"object","description":"Response type for position metrics query","required":["position_id","condition_id","timeframe","volume_usd","buy_volume_usd","sell_volume_usd","fees","txns","buys","sells","unique_traders","price_open","price_high","price_low","price_close"],"properties":{"position_id":{"type":"string"},"condition_id":{"type":"string"},"timeframe":{"type":"string"},"volume_usd":{"type":"number","format":"double"},"buy_volume_usd":{"type":"number","format":"double"},"sell_volume_usd":{"type":"number","format":"double"},"fees":{"type":"number","format":"double"},"txns":{"type":"integer","format":"int32"},"buys":{"type":"integer","format":"int32"},"sells":{"type":"integer","format":"int32"},"unique_traders":{"type":"integer","format":"int32"},"price_open":{"type":"number","format":"double"},"price_high":{"type":"number","format":"double"},"price_low":{"type":"number","format":"double"},"price_close":{"type":"number","format":"double"}}},"PositionPnlSortBy":{"type":"string","enum":["realized_pnl_usd","buy_usd","sell_usd","redemption_usd","total_buys","total_sells","total_shares_bought","total_shares_sold","avg_entry_price","avg_exit_price","total_fees","first_trade_at","last_trade_at","current_value","realized_pnl_pct","title"]},"PositionStatus":{"type":"string","description":"Position status filter for open/closed positions.","enum":["open","closed"]},"PositionVolumeChartResponse":{"type":"object","required":["volumes","has_more"],"properties":{"volumes":{"type":"array","items":{"$ref":"#/components/schemas/PositionVolumeDataPoint"}},"has_more":{"type":"boolean"}}},"PositionVolumeDataPoint":{"type":"object","required":["t","v","bv","sv","tc","btc","stc"],"properties":{"t":{"type":"integer","format":"int64"},"v":{"type":"number","format":"double"},"bv":{"type":"number","format":"double"},"sv":{"type":"number","format":"double"},"tc":{"type":"integer","format":"int32"},"btc":{"type":"integer","format":"int32"},"stc":{"type":"integer","format":"int32"}}},"PositionsConvertedTrade":{"type":"object","description":"Output payload for NegRisk PositionsConverted trades\n(convert NO-position tokens → YES tokens + collateral).","required":["id","hash","trader","market_id","index_set","shares_amount","exchange"],"properties":{"id":{"type":"string"},"hash":{"type":"string"},"block":{"type":["integer","null"],"format":"int64","minimum":0},"confirmed_at":{"type":["integer","null"],"format":"int64","minimum":0},"received_at":{"type":["integer","null"],"format":"int64","minimum":0},"log_index":{"type":["integer","null"],"format":"int64","minimum":0},"block_index":{"type":["integer","null"],"format":"int64","minimum":0},"trader":{"$ref":"#/components/schemas/TraderInfo"},"market_id":{"type":"string","description":"NegRisk umbrella market ID"},"index_set":{"type":"string","description":"Bitmask of question indices whose NO tokens are being converted"},"shares_amount":{"type":"number","format":"double"},"exchange":{"$ref":"#/components/schemas/PolymarketExchange"}}},"PredictionCandlestickBar":{"type":"object","required":["t"],"properties":{"l":{"type":["number","null"],"format":"double"},"h":{"type":["number","null"],"format":"double"},"o":{"type":["number","null"],"format":"double"},"c":{"type":["number","null"],"format":"double"},"v":{"type":["number","null"],"format":"double"},"t":{"type":"integer","format":"int64","minimum":0},"tc":{"type":["integer","null"],"format":"int32"},"m":{"type":["number","null"],"format":"double"}}},"PriceJump":{"type":"object","required":["from","to","price_before","price_after","change_pct","direction","volume","trades_count","condition_id"],"properties":{"from":{"type":"integer","format":"int64","minimum":0},"to":{"type":"integer","format":"int64","minimum":0},"price_before":{"type":"number","format":"double"},"price_after":{"type":"number","format":"double"},"change_pct":{"type":"number","format":"double"},"direction":{"type":"string"},"volume":{"type":"number","format":"double"},"trades_count":{"type":"integer","format":"int32"},"condition_id":{"type":"string"}}},"QuestionEmergencyResolvedEvent":{"type":"object","description":"UMA CTF Adapter: admin emergency resolution.","required":["id","hash","oracle_contract","condition_id"],"properties":{"id":{"type":"string"},"hash":{"type":"string"},"block":{"type":["integer","null"],"format":"int64","minimum":0},"confirmed_at":{"type":["integer","null"],"format":"int64","minimum":0},"received_at":{"type":["integer","null"],"format":"int64","minimum":0},"log_index":{"type":["integer","null"],"format":"int64","minimum":0},"block_index":{"type":["integer","null"],"format":"int64","minimum":0},"oracle_contract":{"type":"string"},"condition_id":{"type":"string"},"proposed_outcome":{"type":["string","null"]},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"slug":{"type":["string","null"]},"event_slug":{"type":["string","null"]}}},"QuestionFlaggedEvent":{"type":"object","description":"UMA CTF Adapter: market flagged for emergency resolution.","required":["id","hash","oracle_contract","condition_id"],"properties":{"id":{"type":"string"},"hash":{"type":"string"},"block":{"type":["integer","null"],"format":"int64","minimum":0},"confirmed_at":{"type":["integer","null"],"format":"int64","minimum":0},"received_at":{"type":["integer","null"],"format":"int64","minimum":0},"log_index":{"type":["integer","null"],"format":"int64","minimum":0},"block_index":{"type":["integer","null"],"format":"int64","minimum":0},"oracle_contract":{"type":"string"},"condition_id":{"type":"string"},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"slug":{"type":["string","null"]},"event_slug":{"type":["string","null"]}}},"QuestionInitializedEvent":{"type":"object","description":"UMA CTF Adapter: questionID first initialized on-chain.","required":["id","hash","oracle_contract","condition_id","creator","reward_token","reward","proposal_bond"],"properties":{"id":{"type":"string"},"hash":{"type":"string"},"block":{"type":["integer","null"],"format":"int64","minimum":0},"confirmed_at":{"type":["integer","null"],"format":"int64","minimum":0},"received_at":{"type":["integer","null"],"format":"int64","minimum":0},"log_index":{"type":["integer","null"],"format":"int64","minimum":0},"block_index":{"type":["integer","null"],"format":"int64","minimum":0},"oracle_contract":{"type":"string"},"condition_id":{"type":"string"},"creator":{"type":"string"},"reward_token":{"type":"string"},"reward":{"type":"string"},"proposal_bond":{"type":"string"},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"slug":{"type":["string","null"]},"event_slug":{"type":["string","null"]}}},"QuestionPausedEvent":{"type":"object","description":"UMA CTF Adapter: market paused by admin.","required":["id","hash","oracle_contract","condition_id"],"properties":{"id":{"type":"string"},"hash":{"type":"string"},"block":{"type":["integer","null"],"format":"int64","minimum":0},"confirmed_at":{"type":["integer","null"],"format":"int64","minimum":0},"received_at":{"type":["integer","null"],"format":"int64","minimum":0},"log_index":{"type":["integer","null"],"format":"int64","minimum":0},"block_index":{"type":["integer","null"],"format":"int64","minimum":0},"oracle_contract":{"type":"string"},"condition_id":{"type":"string"},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"slug":{"type":["string","null"]},"event_slug":{"type":["string","null"]}}},"QuestionResetEvent":{"type":"object","description":"UMA CTF Adapter: dispute succeeded, market returns to active.","required":["id","hash","oracle_contract","condition_id"],"properties":{"id":{"type":"string"},"hash":{"type":"string"},"block":{"type":["integer","null"],"format":"int64","minimum":0},"confirmed_at":{"type":["integer","null"],"format":"int64","minimum":0},"received_at":{"type":["integer","null"],"format":"int64","minimum":0},"log_index":{"type":["integer","null"],"format":"int64","minimum":0},"block_index":{"type":["integer","null"],"format":"int64","minimum":0},"oracle_contract":{"type":"string"},"condition_id":{"type":"string"},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"slug":{"type":["string","null"]},"event_slug":{"type":["string","null"]}}},"QuestionResolvedEvent":{"type":"object","description":"UMA CTF Adapter: market resolved with definitive outcome.","required":["id","hash","oracle_contract","condition_id","settled_price"],"properties":{"id":{"type":"string"},"hash":{"type":"string"},"block":{"type":["integer","null"],"format":"int64","minimum":0},"confirmed_at":{"type":["integer","null"],"format":"int64","minimum":0},"received_at":{"type":["integer","null"],"format":"int64","minimum":0},"log_index":{"type":["integer","null"],"format":"int64","minimum":0},"block_index":{"type":["integer","null"],"format":"int64","minimum":0},"oracle_contract":{"type":"string"},"condition_id":{"type":"string"},"settled_price":{"type":"integer","format":"int64"},"proposed_outcome":{"type":["string","null"]},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"slug":{"type":["string","null"]},"event_slug":{"type":["string","null"]}}},"QuestionUnflaggedEvent":{"type":"object","description":"UMA CTF Adapter: flag removed.","required":["id","hash","oracle_contract","condition_id"],"properties":{"id":{"type":"string"},"hash":{"type":"string"},"block":{"type":["integer","null"],"format":"int64","minimum":0},"confirmed_at":{"type":["integer","null"],"format":"int64","minimum":0},"received_at":{"type":["integer","null"],"format":"int64","minimum":0},"log_index":{"type":["integer","null"],"format":"int64","minimum":0},"block_index":{"type":["integer","null"],"format":"int64","minimum":0},"oracle_contract":{"type":"string"},"condition_id":{"type":"string"},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"slug":{"type":["string","null"]},"event_slug":{"type":["string","null"]}}},"QuestionUnpausedEvent":{"type":"object","description":"UMA CTF Adapter: market unpaused.","required":["id","hash","oracle_contract","condition_id"],"properties":{"id":{"type":"string"},"hash":{"type":"string"},"block":{"type":["integer","null"],"format":"int64","minimum":0},"confirmed_at":{"type":["integer","null"],"format":"int64","minimum":0},"received_at":{"type":["integer","null"],"format":"int64","minimum":0},"log_index":{"type":["integer","null"],"format":"int64","minimum":0},"block_index":{"type":["integer","null"],"format":"int64","minimum":0},"oracle_contract":{"type":"string"},"condition_id":{"type":"string"},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"slug":{"type":["string","null"]},"event_slug":{"type":["string","null"]}}},"RedemptionTrade":{"type":"object","description":"Output payload for Redemption trades (payout after market resolution).","required":["id","hash","trader","usd_amount","exchange"],"properties":{"id":{"type":"string"},"hash":{"type":"string"},"block":{"type":["integer","null"],"format":"int64","minimum":0},"confirmed_at":{"type":["integer","null"],"format":"int64","minimum":0},"received_at":{"type":["integer","null"],"format":"int64","minimum":0},"log_index":{"type":["integer","null"],"format":"int64","minimum":0},"block_index":{"type":["integer","null"],"format":"int64","minimum":0},"trader":{"$ref":"#/components/schemas/TraderInfo"},"condition_id":{"type":["string","null"]},"outcome":{"type":["string","null"]},"outcome_index":{"type":["integer","null"],"format":"int32","minimum":0},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"slug":{"type":["string","null"]},"event_slug":{"type":["string","null"]},"usd_amount":{"type":"number","format":"double"},"winning_outcome_index":{"type":["integer","null"],"format":"int32","minimum":0},"position_details":{"type":"array","items":{"$ref":"#/components/schemas/PositionDetail"},"description":"Per-position burn amounts"},"exchange":{"$ref":"#/components/schemas/PolymarketExchange"}}},"RegisterTokenTrade":{"type":"object","description":"Output payload for RegisterToken events (YES/NO token pair registered for a condition).","required":["id","hash","condition_id","token0","token1","exchange"],"properties":{"id":{"type":"string"},"hash":{"type":"string"},"block":{"type":["integer","null"],"format":"int64","minimum":0},"confirmed_at":{"type":["integer","null"],"format":"int64","minimum":0},"received_at":{"type":["integer","null"],"format":"int64","minimum":0},"log_index":{"type":["integer","null"],"format":"int64","minimum":0},"block_index":{"type":["integer","null"],"format":"int64","minimum":0},"condition_id":{"type":"string"},"token0":{"type":"string"},"token1":{"type":"string"},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"slug":{"type":["string","null"]},"event_slug":{"type":["string","null"]},"exchange":{"$ref":"#/components/schemas/PolymarketExchange"}}},"SearchResponse":{"type":"object","properties":{"events":{"type":["array","null"],"items":{"$ref":"#/components/schemas/PolymarketEvent"}},"events_pagination":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PaginationMeta"}]},"markets":{"type":["array","null"],"items":{"$ref":"#/components/schemas/MarketResponse"}},"markets_pagination":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PaginationMeta"}]},"traders":{"type":["array","null"],"items":{"$ref":"#/components/schemas/TraderWithPnl"}},"traders_pagination":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PaginationMeta"}]}}},"SearchSortBy":{"type":"string","description":"Combined sort options valid for both events and markets in search","enum":["volume","txns","unique_traders","relevance","title","creation_date","start_date","end_date","liquidity","holders","end_time","start_time","created_time"]},"SimpleTimeframeMetrics":{"type":"object","properties":{"volume":{"type":"number","format":"double","default":0},"fees":{"type":"number","format":"double","default":0},"txns":{"type":"integer","format":"int32","default":0},"unique_traders":{"type":"integer","format":"int32","default":0}}},"SortDirection":{"type":"string","enum":["asc","desc"]},"SpikeDirection":{"type":"string","description":"Direction filter for spike webhooks.","enum":["up","down","both"]},"SplitTrade":{"type":"object","description":"Output payload for Split trades (deposit collateral → receive outcome tokens).","required":["id","hash","trader","usd_amount","exchange"],"properties":{"id":{"type":"string"},"hash":{"type":"string"},"block":{"type":["integer","null"],"format":"int64","minimum":0},"confirmed_at":{"type":["integer","null"],"format":"int64","minimum":0},"received_at":{"type":["integer","null"],"format":"int64","minimum":0},"log_index":{"type":["integer","null"],"format":"int64","minimum":0},"block_index":{"type":["integer","null"],"format":"int64","minimum":0},"trader":{"$ref":"#/components/schemas/TraderInfo"},"condition_id":{"type":["string","null"]},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"slug":{"type":["string","null"]},"event_slug":{"type":["string","null"]},"usd_amount":{"type":"number","format":"double"},"position_details":{"type":"array","items":{"$ref":"#/components/schemas/PositionDetail"},"description":"Per-position mint amounts"},"exchange":{"$ref":"#/components/schemas/PolymarketExchange"}}},"SpreadRow":{"type":"object","description":"Lightweight row — derived metrics only, no bids/asks JSONB.","required":["ts","position_id","condition_id"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}},"TokenOutcome":{"type":"object","description":"Token outcome (position)","required":["token_id","outcome"],"properties":{"token_id":{"type":"string"},"outcome":{"type":"string"}}},"TradeEvent":{"oneOf":[{"allOf":[{"$ref":"#/components/schemas/OrderFilledTrade"},{"type":"object","required":["trade_type"],"properties":{"trade_type":{"type":"string","enum":["OrderFilled"]}}}]},{"allOf":[{"$ref":"#/components/schemas/OrderFilledTrade"},{"type":"object","required":["trade_type"],"properties":{"trade_type":{"type":"string","enum":["OrdersMatched"]}}}]},{"allOf":[{"$ref":"#/components/schemas/RedemptionTrade"},{"type":"object","required":["trade_type"],"properties":{"trade_type":{"type":"string","enum":["Redemption"]}}}]},{"allOf":[{"$ref":"#/components/schemas/MergeTrade"},{"type":"object","required":["trade_type"],"properties":{"trade_type":{"type":"string","enum":["Merge"]}}}]},{"allOf":[{"$ref":"#/components/schemas/SplitTrade"},{"type":"object","required":["trade_type"],"properties":{"trade_type":{"type":"string","enum":["Split"]}}}]},{"allOf":[{"$ref":"#/components/schemas/PositionsConvertedTrade"},{"type":"object","required":["trade_type"],"properties":{"trade_type":{"type":"string","enum":["PositionsConverted"]}}}]},{"allOf":[{"$ref":"#/components/schemas/CancelledTrade"},{"type":"object","required":["trade_type"],"properties":{"trade_type":{"type":"string","enum":["Cancelled"]}}}]},{"allOf":[{"$ref":"#/components/schemas/QuestionInitializedEvent"},{"type":"object","required":["trade_type"],"properties":{"trade_type":{"type":"string","enum":["Initialization"]}}}]},{"allOf":[{"$ref":"#/components/schemas/AssertionMadeEvent"},{"type":"object","required":["trade_type"],"properties":{"trade_type":{"type":"string","enum":["Proposal"]}}}]},{"allOf":[{"$ref":"#/components/schemas/AssertionDisputedEvent"},{"type":"object","required":["trade_type"],"properties":{"trade_type":{"type":"string","enum":["Dispute"]}}}]},{"allOf":[{"$ref":"#/components/schemas/AssertionSettledEvent"},{"type":"object","required":["trade_type"],"properties":{"trade_type":{"type":"string","enum":["Settled"]}}}]},{"allOf":[{"$ref":"#/components/schemas/QuestionResolvedEvent"},{"type":"object","required":["trade_type"],"properties":{"trade_type":{"type":"string","enum":["Resolution"]}}}]},{"allOf":[{"$ref":"#/components/schemas/ConditionResolutionEvent"},{"type":"object","required":["trade_type"],"properties":{"trade_type":{"type":"string","enum":["ConditionResolution"]}}}]},{"allOf":[{"$ref":"#/components/schemas/QuestionResetEvent"},{"type":"object","required":["trade_type"],"properties":{"trade_type":{"type":"string","enum":["Reset"]}}}]},{"allOf":[{"$ref":"#/components/schemas/QuestionFlaggedEvent"},{"type":"object","required":["trade_type"],"properties":{"trade_type":{"type":"string","enum":["Flag"]}}}]},{"allOf":[{"$ref":"#/components/schemas/QuestionUnflaggedEvent"},{"type":"object","required":["trade_type"],"properties":{"trade_type":{"type":"string","enum":["Unflag"]}}}]},{"allOf":[{"$ref":"#/components/schemas/QuestionPausedEvent"},{"type":"object","required":["trade_type"],"properties":{"trade_type":{"type":"string","enum":["Pause"]}}}]},{"allOf":[{"$ref":"#/components/schemas/QuestionUnpausedEvent"},{"type":"object","required":["trade_type"],"properties":{"trade_type":{"type":"string","enum":["Unpause"]}}}]},{"allOf":[{"$ref":"#/components/schemas/QuestionEmergencyResolvedEvent"},{"type":"object","required":["trade_type"],"properties":{"trade_type":{"type":"string","enum":["ManualResolution"]}}}]},{"allOf":[{"$ref":"#/components/schemas/NegRiskOutcomeReportedEvent"},{"type":"object","required":["trade_type"],"properties":{"trade_type":{"type":"string","enum":["NegRiskOutcomeReported"]}}}]},{"allOf":[{"$ref":"#/components/schemas/RegisterTokenTrade"},{"type":"object","required":["trade_type"],"properties":{"trade_type":{"type":"string","enum":["RegisterToken"]}}}]},{"allOf":[{"$ref":"#/components/schemas/ApprovalTrade"},{"type":"object","required":["trade_type"],"properties":{"trade_type":{"type":"string","enum":["Approval"]}}}]}],"description":"Tagged enum for all trade types — serializes with `\"trade_type\": \"...\"` discriminator\nand only includes fields relevant to each type."},"TradeSide":{"type":"string","enum":["0","1"]},"TradeType":{"type":"string","enum":["0","1","2","3","4","5","6"]},"Trader":{"type":"object","description":"Trader profile info embedded in API responses\n\nCorresponds to SQL function: `pm_build_trader(address, name, pseudonym, profile_image, x_username, verified_badge)`\n\nUsed in:\n- holders endpoints (market/event holders)\n- trades endpoints\n- leaderboard endpoints","required":["address"],"properties":{"address":{"type":"string"},"name":{"type":["string","null"]},"pseudonym":{"type":["string","null"]},"profile_image":{"type":["string","null"]},"x_username":{"type":["string","null"]},"verified_badge":{"type":"boolean"}}},"TraderEventPnlEntry":{"type":"object","description":"Event-level PnL entry","properties":{"event_slug":{"type":["string","null"]},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"markets_traded":{"type":["integer","null"],"format":"int64"},"outcomes_traded":{"type":["integer","null"],"format":"int64"},"total_buys":{"type":["integer","null"],"format":"int64"},"total_sells":{"type":["integer","null"],"format":"int64"},"total_redemptions":{"type":["integer","null"],"format":"int64"},"total_merges":{"type":["integer","null"],"format":"int64"},"total_volume_usd":{"type":["number","null"],"format":"double"},"buy_usd":{"type":["number","null"],"format":"double"},"sell_usd":{"type":["number","null"],"format":"double"},"redemption_usd":{"type":["number","null"],"format":"double"},"merge_usd":{"type":["number","null"],"format":"double"},"realized_pnl_usd":{"type":["number","null"],"format":"double"},"winning_markets":{"type":["integer","null"],"format":"int64"},"losing_markets":{"type":["integer","null"],"format":"int64"},"total_fees":{"type":["number","null"],"format":"double"},"first_trade_at":{"type":["integer","null"],"format":"int64"},"last_trade_at":{"type":["integer","null"],"format":"int64"}}},"TraderInfo":{"type":"object","description":"Trader profile info - backwards compatibility","required":["address"],"properties":{"address":{"type":"string"},"name":{"type":["string","null"]},"pseudonym":{"type":["string","null"]},"profile_image":{"type":["string","null"]},"x_username":{"type":["string","null"]},"verified_badge":{"type":"boolean"}}},"TraderMarketPnlEntry":{"type":"object","description":"Market-level PnL entry","properties":{"condition_id":{"type":["string","null"]},"event_slug":{"type":["string","null"]},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"outcomes_traded":{"type":["integer","null"],"format":"int64"},"total_buys":{"type":["integer","null"],"format":"int64"},"total_sells":{"type":["integer","null"],"format":"int64"},"total_redemptions":{"type":["integer","null"],"format":"int64"},"total_merges":{"type":["integer","null"],"format":"int64"},"buy_usd":{"type":["number","null"],"format":"double"},"sell_usd":{"type":["number","null"],"format":"double"},"redemption_usd":{"type":["number","null"],"format":"double"},"merge_usd":{"type":["number","null"],"format":"double"},"realized_pnl_usd":{"type":["number","null"],"format":"double"},"winning_outcomes":{"type":["integer","null"],"format":"int64"},"total_fees":{"type":["number","null"],"format":"double"},"first_trade_at":{"type":["integer","null"],"format":"int64"},"last_trade_at":{"type":["integer","null"],"format":"int64"}}},"TraderOutcomePnlEntry":{"type":"object","description":"Outcome-level PnL entry (per outcome token / position_id)","properties":{"position_id":{"type":["string","null"]},"condition_id":{"type":["string","null"]},"market_slug":{"type":["string","null"]},"event_slug":{"type":["string","null"]},"title":{"type":["string","null"]},"image_url":{"type":["string","null"]},"outcome":{"type":["string","null"]},"outcome_index":{"type":["integer","null"],"format":"int32"},"won":{"type":["boolean","null"],"description":"TRUE = won, FALSE = lost, NULL = open or sold before resolution"},"total_buys":{"type":["integer","null"],"format":"int64"},"total_sells":{"type":["integer","null"],"format":"int64"},"total_shares_bought":{"type":["number","null"],"format":"double"},"total_shares_sold":{"type":["number","null"],"format":"double"},"total_buy_usd":{"type":["number","null"],"format":"double"},"total_sell_usd":{"type":["number","null"],"format":"double"},"redemption_usd":{"type":["number","null"],"format":"double","description":"Payout on redemption (non-zero only if won)"},"avg_entry_price":{"type":["number","null"],"format":"double","description":"VWAP price paid per share across all buys (0–1)"},"avg_exit_price":{"type":["number","null"],"format":"double","description":"VWAP price received per share across all sells (0–1)"},"realized_pnl_usd":{"type":["number","null"],"format":"double"},"total_fees":{"type":["number","null"],"format":"double"},"first_trade_at":{"type":["integer","null"],"format":"int64"},"last_trade_at":{"type":["integer","null"],"format":"int64"},"current_price":{"type":["number","null"],"format":"double","description":"Last traded price for this outcome (0–1). NULL if market_outcomes has no price yet."},"current_shares_balance":{"type":["number","null"],"format":"double","description":"Current shares held: balance / 1e6."},"current_value":{"type":["number","null"],"format":"double","description":"Estimated current USD value of held shares: (balance / 1e6) * current_price.\nOnly meaningful for open positions (balance above dust threshold)."},"realized_pnl_pct":{"type":["number","null"],"format":"double","description":"Realized PnL as a percentage of total spend: (realized_pnl_usd / total_buy_usd) * 100.\nNULL when total_buy_usd = 0."}}},"TraderPnlSummary":{"type":"object","description":"Trader's global PnL summary (single trader)","properties":{"trader":{"type":["string","null"]},"realized_pnl_usd":{"type":["number","null"],"format":"double"},"events_traded":{"type":["integer","null"],"format":"int64"},"markets_traded":{"type":["integer","null"],"format":"int64"},"total_buys":{"type":["integer","null"],"format":"int64"},"total_sells":{"type":["integer","null"],"format":"int64"},"total_redemptions":{"type":["integer","null"],"format":"int64"},"total_merges":{"type":["integer","null"],"format":"int64"},"total_volume_usd":{"type":["number","null"],"format":"double"},"buy_volume_usd":{"type":["number","null"],"format":"double"},"sell_volume_usd":{"type":["number","null"],"format":"double"},"redemption_volume_usd":{"type":["number","null"],"format":"double"},"merge_volume_usd":{"type":["number","null"],"format":"double"},"markets_won":{"type":["integer","null"],"format":"int64"},"markets_lost":{"type":["integer","null"],"format":"int64"},"market_win_rate_pct":{"type":["number","null"],"format":"double"},"avg_pnl_per_market":{"type":["number","null"],"format":"double"},"avg_pnl_per_trade":{"type":["number","null"],"format":"double"},"avg_hold_time_seconds":{"type":["number","null"],"format":"double"},"total_fees":{"type":["number","null"],"format":"double"},"best_trade_pnl_usd":{"type":["number","null"],"format":"double"},"best_trade_condition_id":{"type":["string","null"]},"first_trade_at":{"type":["integer","null"],"format":"int64"},"last_trade_at":{"type":["integer","null"],"format":"int64"}}},"TraderVolumeChartResponse":{"type":"object","required":["volumes","has_more"],"properties":{"volumes":{"type":"array","items":{"$ref":"#/components/schemas/TraderVolumeDataPoint"}},"has_more":{"type":"boolean"}}},"TraderVolumeDataPoint":{"type":"object","required":["t","v","bv","sv","tc","btc","stc"],"properties":{"t":{"type":"integer","format":"int64"},"v":{"type":"number","format":"double"},"bv":{"type":"number","format":"double"},"sv":{"type":"number","format":"double"},"tc":{"type":"integer","format":"int32"},"btc":{"type":"integer","format":"int32"},"stc":{"type":"integer","format":"int32"}}},"TraderWithPnl":{"allOf":[{"$ref":"#/components/schemas/Trader"},{"type":"object","properties":{"pnl":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/TraderPnlSummary"}]}}}]},"WebhookAssetSymbol":{"type":"string","description":"Crypto asset symbols accepted by `asset_price_tick` and `asset_price_window_update` filters.","enum":["BTC","ETH","SOL","XRP","DOGE","BNB","HYPE"]},"WebhookTimeframe":{"type":"string","description":"Timeframe values accepted by webhook metric, milestone, spike, and asset-price filters.","enum":["1m","5m","15m","30m","1h","4h","6h","1d","24h","7d","30d"]}}}} \ No newline at end of file +{"openapi":"3.1.0","info":{"title":"Polymarket API","description":"RESTful API for querying Polymarket prediction markets data including events, markets, traders, holders, and real-time metrics","license":{"name":""},"version":"1.0.0"},"servers":[{"url":"https://api.struct.to/v1","description":"Production"}],"paths":{"/polymarket/asset-history":{"get":{"tags":["Assets"],"summary":"Get Asset Price History","description":"Returns historical price data for supported crypto assets from Polymarket API","operationId":"get_asset_history","parameters":[{"name":"asset_symbol","in":"query","description":"Asset ticker: BTC, ETH, XRP, SOL, DOGE, BNB, HYPE","required":true,"schema":{"type":"string"},"example":"BTC"},{"name":"variant","in":"query","description":"Time window: 5m, 15m, 1h, 4h, 1d","required":true,"schema":{"type":"string"},"example":"1h"},{"name":"from","in":"query","description":"Start timestamp in seconds (Unix epoch, inclusive)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp in seconds (Unix epoch, inclusive)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"limit","in":"query","description":"Number of results (default: 10, max: 100)","required":false,"schema":{"type":"integer","format":"int64"},"example":10},{"name":"pagination_key","in":"query","description":"Cursor from previous response for keyset pagination. Pass the pagination_key from the previous page to fetch the next page.","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AssetPriceHistoryRow"}}}}},"400":{"description":"Bad request - missing or invalid parameters"},"500":{"description":"Internal server error"}}}},"/polymarket/events":{"get":{"tags":["Events"],"summary":"Get events","description":"Retrieve a paginated list of events with filtering, sorting, and optional nested tags/markets","operationId":"get_events","parameters":[{"name":"id","in":"query","description":"Filter by event ID(s) - comma-separated (max 50). Cannot be used with 'event_slugs'. Example: id=99600,99601,99583","required":false,"schema":{"type":"string"}},{"name":"event_slugs","in":"query","description":"Filter by event slug(s) - comma-separated (max 50). Cannot be used with 'id'. Example: event_slugs=will-trump-win,bitcoin-100k","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","description":"Search in title and description (3-100 characters). Example: search=trump","required":false,"schema":{"type":"string"}},{"name":"sort_by","in":"query","description":"Sort: volume, txns, unique_traders, title, creation_date, start_date, end_date, relevance (relevance only works in search mode) (default: volume)","required":false,"schema":{"$ref":"#/components/schemas/EventSortBy"}},{"name":"sort_dir","in":"query","description":"Sort direction: asc, desc (default: desc)","required":false,"schema":{"$ref":"#/components/schemas/SortDirection"}},{"name":"timeframe","in":"query","description":"Metrics timeframe: 1m, 5m, 30m, 1h, 6h, 24h, 7d, 30d (default: 24h)","required":false,"schema":{"$ref":"#/components/schemas/MetricsTimeframe"}},{"name":"status","in":"query","description":"Filter by status: open, closed, or all (default: all)","required":false,"schema":{"$ref":"#/components/schemas/MarketStatus"}},{"name":"categories","in":"query","description":"Comma-separated category filters","required":false,"schema":{"type":"string"}},{"name":"exclude_categories","in":"query","description":"Comma-separated categories to exclude","required":false,"schema":{"type":"string"}},{"name":"tags","in":"query","description":"Filter by tag slug(s) - comma-separated (max 50). Example: tags=sports,football,crypto","required":false,"schema":{"type":"string"}},{"name":"exclude_tags","in":"query","description":"Comma-separated tag slugs to exclude","required":false,"schema":{"type":"string"}},{"name":"min_volume","in":"query","description":"Minimum volume in selected timeframe","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_volume","in":"query","description":"Maximum volume in selected timeframe","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_txns","in":"query","description":"Minimum transactions in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"max_txns","in":"query","description":"Maximum transactions in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"min_unique_traders","in":"query","description":"Minimum unique traders in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"max_unique_traders","in":"query","description":"Maximum unique traders in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"include_tags","in":"query","description":"Include tags array (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_markets","in":"query","description":"Include markets array with outcomes (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_metrics","in":"query","description":"Include metrics object with all timeframes (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key","required":false,"schema":{"type":"string"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of Polymarket events with nested tags, markets, and series. Response includes `pagination: { has_more, pagination_key }` for cursor-based pagination.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PolymarketEvent"}}}}},"400":{"description":"Bad request - validation error (search length, array limits, conflicting params)"}}}},"/polymarket/events/chart":{"get":{"tags":["Events"],"summary":"Get event chart","description":"Retrieve price data over time for up to 4 markets with highest YES outcome (outcome_index 0) prices in an event. Perfect for rendering multi-line charts showing price movement across top markets. TradingView-style: resolution parameter determines both candle size and implicit lookback period.","operationId":"get_event_chart","parameters":[{"name":"event_slug","in":"query","description":"Event slug (required)","required":true,"schema":{"type":"string"}},{"name":"condition_ids","in":"query","description":"Comma-separated condition IDs to include (max 4, optional)","required":false,"schema":{"type":"string"}},{"name":"market_slugs","in":"query","description":"Comma-separated market slugs to include (max 4, optional). Use either condition_ids or market_slugs, not both","required":false,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Time interval with implicit lookback: 1H (1 hour), 6H (6 hours), 1D (1 day), 1W (1 week), 1M (30 days), ALL (all data) (required)","required":true,"schema":{"$ref":"#/components/schemas/ChartResolution"}}],"responses":{"200":{"description":"Price data over time for up to 4 markets with highest YES odds","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventMarketChartOutcome"}}}}}}}},"/polymarket/events/metrics":{"get":{"tags":["Events"],"summary":"Get event metrics","description":"Retrieve volume, transaction, and trader metrics for an event. Supports single timeframe (e.g., '1m'), multiple timeframes (e.g., '1m,5m,1h'), or 'all' to get all available timeframes.","operationId":"get_event_metrics","parameters":[{"name":"event_slug","in":"query","description":"Event slug","required":true,"schema":{"type":"string"}},{"name":"timeframe","in":"query","description":"Timeframe: single (1m, 5m, 30m, 1h, 6h, 24h, 7d, 30d), comma-separated (1m,5m,1h), or 'all'","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Event metrics for the specified timeframe(s). Returns single object for one timeframe, array for multiple.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventMetricsResponse"}}}},"400":{"description":"Invalid timeframe"}}}},"/polymarket/events/outcomes":{"get":{"tags":["Events"],"summary":"Get event market outcomes","description":"Returns the winning outcome name for each resolved market in an event, keyed by market slug. Useful for quickly checking which outcomes won across a series.","operationId":"get_event_outcomes","parameters":[{"name":"event_slug","in":"query","description":"Event slug (required)","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Number of resolved markets per page (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key for fetching next page","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Map of market_slug → winning outcome name with pagination metadata","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}}}}},"400":{"description":"Missing event_slug parameter"}}}},"/polymarket/events/slug/{event_slug}":{"get":{"tags":["Events"],"summary":"Get event by slug","description":"Retrieve a single event by its slug with optional nested tags, markets, and metrics","operationId":"get_event_by_slug","parameters":[{"name":"event_slug","in":"path","description":"Event slug","required":true,"schema":{"type":"string"}},{"name":"include_tags","in":"query","description":"Include tags array (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_markets","in":"query","description":"Include markets array with outcomes (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_metrics","in":"query","description":"Include metrics object with all timeframes (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Event with nested tags, markets, and series","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PolymarketEvent"}}}},"404":{"description":"Event not found"}}}},"/polymarket/events/{identifier}":{"get":{"tags":["Events"],"summary":"Get event by ID or slug","description":"Retrieve a single event by its numeric ID or slug with optional nested tags, markets, and metrics","operationId":"get_event","parameters":[{"name":"identifier","in":"path","description":"Event ID or slug","required":true,"schema":{"type":"string"}},{"name":"include_tags","in":"query","description":"Include tags array (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_markets","in":"query","description":"Include markets array with outcomes (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_metrics","in":"query","description":"Include metrics object with all timeframes (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Event with nested tags, markets, and series","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PolymarketEvent"}}}},"404":{"description":"Event not found"}}}},"/polymarket/holders/markets":{"get":{"tags":["Holders"],"summary":"Get market holders","description":"Retrieve holders of a market grouped by outcome, sorted by shares held. Identify the market with either `condition_id` or `market_slug` — exactly one must be provided. Set `include_pnl=true` to include a nested holder `pnl` object.","operationId":"get_market_holders","parameters":[{"name":"condition_id","in":"query","description":"Market condition ID (0x-prefixed hex)","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (e.g. `will-trump-win`)","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"min_shares","in":"query","description":"Minimum shares held (decimal string)","required":false,"schema":{"type":"string"}},{"name":"max_shares","in":"query","description":"Maximum shares held (decimal string)","required":false,"schema":{"type":"string"}},{"name":"include_pnl","in":"query","description":"Include nested holder PnL data (default: false, +1 credit)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Market holders grouped by outcome (sorted by shares DESC). Holder `pnl` is included only when `include_pnl=true`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarketHoldersResponse"}}}},"404":{"description":"Market not found"}}}},"/polymarket/holders/markets/history":{"get":{"tags":["Holders"],"summary":"Get market holders history","description":"Retrieve historical holder count snapshots for a market over a time range. Identify the market with either `condition_id` or `market_slug` — exactly one must be provided.","operationId":"get_market_holders_history","parameters":[{"name":"condition_id","in":"query","description":"Market condition ID (0x-prefixed hex)","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (e.g. `will-trump-win`)","required":false,"schema":{"type":"string"}},{"name":"hours","in":"query","description":"Time range in hours (default: 24, max: 336 = 14 days)","required":false,"schema":{"type":"number","format":"double"}}],"responses":{"200":{"description":"Market holder count history with automatic granularity (1m/5m/15m/1h/6h buckets)","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/HolderHistoryCandle"}}}}},"404":{"description":"Market not found"}}}},"/polymarket/holders/positions/{position_id}":{"get":{"tags":["Holders"],"summary":"Get position holders","description":"Retrieve holders of a specific position (ERC1155 token), sorted by shares held. Set `include_pnl=true` to include nested holder PnL. Uses cursor-based pagination for efficient traversal.","operationId":"get_position_holders","parameters":[{"name":"position_id","in":"path","description":"Position ID (ERC1155 token ID)","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key","required":false,"schema":{"type":"string"}},{"name":"min_shares","in":"query","description":"Minimum shares held (decimal string)","required":false,"schema":{"type":"string"}},{"name":"max_shares","in":"query","description":"Maximum shares held (decimal string)","required":false,"schema":{"type":"string"}},{"name":"include_pnl","in":"query","description":"Include nested holder PnL data (default: false, +1 credit)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Position holders (sorted by shares DESC). Holder `pnl` is included only when `include_pnl=true`. Response includes `pagination: { has_more, pagination_key }` for cursor-based pagination.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PositionHoldersResponse"}}}},"404":{"description":"Position not found"}}}},"/polymarket/holders/positions/{position_id}/history":{"get":{"tags":["Holders"],"summary":"Get position holders history","description":"Retrieve historical holder count snapshots for a position over a time range","operationId":"get_position_holders_history","parameters":[{"name":"position_id","in":"path","description":"Position ID (ERC1155 token ID)","required":true,"schema":{"type":"string"}},{"name":"hours","in":"query","description":"Time range in hours (default: 24, max: 336 = 14 days)","required":false,"schema":{"type":"number","format":"double"}}],"responses":{"200":{"description":"Position holder count history with automatic granularity (1m/5m/15m/1h/6h buckets)","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/HolderHistoryCandle"}}}}},"404":{"description":"Position not found"}}}},"/polymarket/market":{"get":{"tags":["Market"],"summary":"Get markets","description":"Retrieve a paginated list of markets with filtering, sorting, and optional nested tags/events/metrics","operationId":"list_markets","parameters":[{"name":"condition_ids","in":"query","description":"Filter by condition ID(s) - comma-separated (max 50)","required":false,"schema":{"type":"string"}},{"name":"question_ids","in":"query","description":"Filter by question ID(s) - comma-separated (max 50)","required":false,"schema":{"type":"string"}},{"name":"market_ids","in":"query","description":"Filter by market ID(s) - comma-separated (max 50)","required":false,"schema":{"type":"string"}},{"name":"market_slugs","in":"query","description":"Filter by market slug(s) - comma-separated (max 50)","required":false,"schema":{"type":"string"}},{"name":"event_slugs","in":"query","description":"Filter by event slug(s) - comma-separated (max 50)","required":false,"schema":{"type":"string"}},{"name":"position_ids","in":"query","description":"Filter by position ID(s) - comma-separated (max 50)","required":false,"schema":{"type":"string"}},{"name":"search","in":"query","description":"Search in title (3-100 characters)","required":false,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Filter by status: open, closed, or all (default: all)","required":false,"schema":{"$ref":"#/components/schemas/MarketStatus"}},{"name":"sort_by","in":"query","description":"Sort: volume, txns, unique_traders, liquidity, holders, total_daily_rate, end_time, start_time, created_time, relevance","required":false,"schema":{"$ref":"#/components/schemas/MarketSortBy"}},{"name":"sort_dir","in":"query","description":"Sort direction: asc, desc (default: desc)","required":false,"schema":{"$ref":"#/components/schemas/SortDirection"}},{"name":"timeframe","in":"query","description":"Metrics timeframe: 1m, 5m, 30m, 1h, 6h, 24h, 7d, 30d (default: 24h)","required":false,"schema":{"$ref":"#/components/schemas/MetricsTimeframe"}},{"name":"min_volume","in":"query","description":"Minimum total volume USD","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_volume","in":"query","description":"Maximum total volume USD","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_liquidity","in":"query","description":"Minimum liquidity USD","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_liquidity","in":"query","description":"Maximum liquidity USD","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_txns","in":"query","description":"Minimum transactions in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"max_txns","in":"query","description":"Maximum transactions in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"min_unique_traders","in":"query","description":"Minimum unique traders in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"max_unique_traders","in":"query","description":"Maximum unique traders in selected timeframe","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"min_holders","in":"query","description":"Minimum total holders","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"max_holders","in":"query","description":"Maximum total holders","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"categories","in":"query","description":"Comma-separated category filters (max 50)","required":false,"schema":{"type":"string"}},{"name":"exclude_categories","in":"query","description":"Comma-separated categories to exclude","required":false,"schema":{"type":"string"}},{"name":"tags","in":"query","description":"Filter by tag(s) - comma-separated (max 50)","required":false,"schema":{"type":"string"}},{"name":"exclude_tags","in":"query","description":"Comma-separated tags to exclude","required":false,"schema":{"type":"string"}},{"name":"start_time","in":"query","description":"Filter markets with end_time >= start_time (Unix timestamp)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"end_time","in":"query","description":"Filter markets with end_time <= end_time (Unix timestamp)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"include_tags","in":"query","description":"Include tags array (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_event","in":"query","description":"Include event object (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_metrics","in":"query","description":"Include all timeframe metrics (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 100)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key","required":false,"schema":{"type":"string"}},{"name":"has_rewards","in":"query","description":"Only return markets that have CLOB rewards (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"List of markets with metadata, outcomes, tags, event, and metrics. Response includes `pagination: { has_more, pagination_key }` for cursor-based pagination.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MarketResponse"}}}}},"400":{"description":"Bad request - validation error (search length, array limits, conflicting params)"}}}},"/polymarket/market/bonds":{"get":{"tags":["Bonds"],"summary":"Get bonds","description":"Retrieve a list of bond markets sorted by yield, filtered by probability and time to expiry","operationId":"get_bonds","parameters":[{"name":"min_probability","in":"query","description":"Minimum probability threshold (default: 0.85)","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_hours","in":"query","description":"Maximum hours until market end","required":false,"schema":{"type":"number","format":"double"}},{"name":"limit","in":"query","description":"Number of results (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor for pagination: end_date (unix epoch) of the last item from the previous page","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"List of bond markets sorted by yield","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BondMarket"}}}}}}}},"/polymarket/market/candlestick":{"get":{"tags":["Market"],"summary":"Get market candlesticks by condition_id","description":"Retrieve OHLCV candlestick data for a market by its condition_id","operationId":"get_market_candlestick","parameters":[{"name":"condition_id","in":"query","description":"Market condition ID (required)","required":true,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Candle interval: 1, 5, 15, 30, 60, 240, D, 1D","required":true,"schema":{"$ref":"#/components/schemas/CandlestickResolution"}},{"name":"count_back","in":"query","description":"Number of candles (max: 2500)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"from","in":"query","description":"Start timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"OHLCV candlestick data","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PredictionCandlestickBar"}}}}}}}},"/polymarket/market/chart":{"get":{"tags":["Market"],"summary":"Get market chart","description":"Retrieve price data over time for up to 4 position outcomes in a market condition. TradingView-style: resolution parameter determines both candle size and implicit lookback period. Auto-selects the 4 most active outcomes if position_ids not specified.","operationId":"get_chart","parameters":[{"name":"condition_id","in":"query","description":"Market condition ID or market_slug (one required)","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (alternative to condition_id)","required":false,"schema":{"type":"string"}},{"name":"position_ids","in":"query","description":"Comma-separated list of position IDs (max 4, optional). Auto-selected if not provided","required":false,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Time interval with implicit lookback: 1H (1 hour), 6H (6 hours), 1D (1 day), 1W (1 week), 1M (30 days), ALL (all data) (required)","required":true,"schema":{"$ref":"#/components/schemas/ChartResolution"}}],"responses":{"200":{"description":"Price data over time for up to 4 market outcomes","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PositionChartOutcome"}}}}}}}},"/polymarket/market/metrics":{"get":{"tags":["Market"],"summary":"Get market metrics","description":"Retrieve volume, transaction, and trader metrics for a market. Supports single timeframe (e.g., '1m'), multiple timeframes (e.g., '1m,5m,1h'), or 'all' to get all available timeframes.","operationId":"get_market_metrics","parameters":[{"name":"condition_id","in":"query","description":"Market condition ID","required":true,"schema":{"type":"string"}},{"name":"timeframe","in":"query","description":"Timeframe: single (1m, 5m, 30m, 1h, 6h, 24h, 7d, 30d), comma-separated (1m,5m,1h), or 'all'","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Market metrics for the specified timeframe(s). Returns single object for one timeframe, array for multiple.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConditionMetricsResponse"}}}},"400":{"description":"Invalid timeframe"}}}},"/polymarket/market/position/candlestick":{"get":{"tags":["Market"],"summary":"Get position candlesticks by position_id","description":"Retrieve OHLCV candlestick data for a specific position by its position_id","operationId":"get_position_candlestick","parameters":[{"name":"position_id","in":"query","description":"Position/token ID (required)","required":true,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Candle interval: 1, 5, 15, 30, 60, 240, D, 1D","required":true,"schema":{"$ref":"#/components/schemas/CandlestickResolution"}},{"name":"count_back","in":"query","description":"Number of candles (max: 2500)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"from","in":"query","description":"Start timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"OHLCV candlestick data","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PredictionCandlestickBar"}}}}}}}},"/polymarket/market/position/metrics":{"get":{"tags":["Market"],"summary":"Get position metrics","description":"Retrieve volume, transaction, and trader metrics for a specific position. Supports single timeframe (e.g., '1m'), multiple timeframes (e.g., '1m,5m,1h'), or 'all' to get all available timeframes.","operationId":"get_position_metrics","parameters":[{"name":"position_id","in":"query","description":"Position/token ID","required":true,"schema":{"type":"string"}},{"name":"timeframe","in":"query","description":"Timeframe: single (1m, 5m, 30m, 1h, 6h, 24h, 7d, 30d), comma-separated (1m,5m,1h), or 'all'","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Position metrics for the specified timeframe(s). Returns single object for one timeframe, array for multiple.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PositionMetricsResponse"}}}},"400":{"description":"Invalid timeframe"}}}},"/polymarket/market/position/volume-chart":{"get":{"tags":["Market"],"summary":"Get position volume chart","description":"Retrieve volume over time for a specific position with buy/sell breakdown","operationId":"get_position_volume_chart","parameters":[{"name":"position_id","in":"query","description":"Position/token ID (required)","required":true,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Time interval: 1, 5, 15, 30, 60, 240, D, 1D (default: 60)","required":false,"schema":{"$ref":"#/components/schemas/CandlestickResolution"}},{"name":"count_back","in":"query","description":"Number of data points (max: 2500)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"from","in":"query","description":"Start timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Volume with buy/sell breakdown over time","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PositionVolumeDataPoint"}}}}}}}},"/polymarket/market/price-jumps":{"get":{"tags":["Market"],"summary":"Detect price jumps","description":"Scan candles for significant price movements. Returns jumps with from/to timestamps in milliseconds, directly usable as trades API time range parameters to identify traders who traded before or during the movement.","operationId":"get_price_jumps","parameters":[{"name":"condition_id","in":"query","description":"Market condition ID (one of condition_id or market_slug required)","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (resolved to condition_id)","required":false,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Candle resolution in minutes: 1, 5, 15, 30, 60, 240 (default: 15)","required":false,"schema":{"type":"string"}},{"name":"min_change_pct","in":"query","description":"Minimum relative percent change to qualify as a jump (default: 10.0)","required":false,"schema":{"type":"number","format":"double"}},{"name":"lookback","in":"query","description":"Number of candles to scan back from now (default: 1440, max: 2500)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"offset","in":"query","description":"Offset in candles from now — window is [now - (lookback + offset) * resolution, now - offset * resolution] (default: 0)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Price jumps sorted by timestamp descending","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PriceJump"}}}}}}}},"/polymarket/market/slug/{market_slug}":{"get":{"tags":["Market"],"summary":"Get market by slug","description":"Retrieve a single market by its slug with optional nested tags, event, and metrics","operationId":"get_market_by_slug","parameters":[{"name":"market_slug","in":"path","description":"Market slug (e.g. `will-trump-win`)","required":true,"schema":{"type":"string"}},{"name":"include_tags","in":"query","description":"Include tags array (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_event","in":"query","description":"Include event object (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_metrics","in":"query","description":"Include all timeframe metrics (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Market with metadata, outcomes, tags, event, and metrics","content":{"application/json":{"schema":{"type":"object","description":"Formatted market response with structured metrics, tags, outcomes, and event","required":["condition_id","status"],"properties":{"condition_id":{"type":"string"},"id":{"type":["string","null"]},"market_slug":{"type":["string","null"]},"question":{"type":["string","null"]},"title":{"type":["string","null"]},"description":{"type":["string","null"]},"image_url":{"type":["string","null"]},"oracle":{"type":["string","null"]},"status":{"type":"string"},"created_time":{"type":["integer","null"],"format":"int64"},"start_time":{"type":["integer","null"],"format":"int64"},"game_start_time":{"type":["integer","null"],"format":"int64"},"closed_time":{"type":["integer","null"],"format":"int64"},"end_time":{"type":["integer","null"],"format":"int64"},"accepting_orders":{"type":["boolean","null"]},"uma_resolution_status":{"type":["string","null"]},"is_neg_risk":{"type":["boolean","null"]},"market_maker_address":{"type":["string","null"]},"creator":{"type":["string","null"]},"category":{"type":["string","null"]},"volume_usd":{"type":["number","null"],"format":"double"},"liquidity_usd":{"type":["number","null"],"format":"double"},"highest_probability":{"type":["number","null"],"format":"double"},"total_holders":{"type":["integer","null"],"format":"int64"},"total_daily_rate":{"type":["number","null"],"format":"double"},"winning_outcome":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/MarketOutcome"}]},"outcomes":{"type":"array","items":{"$ref":"#/components/schemas/MarketOutcome"}},"clob_rewards":{"type":"array","items":{"$ref":"#/components/schemas/ClobReward"}},"tags":{"type":"array","items":{"type":"string"}},"event_slug":{"type":["string","null"]},"resolution_source":{"type":["string","null"]},"metrics":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/SimpleTimeframeMetrics"},"propertyNames":{"type":"string"}},"relevance_score":{"type":["number","null"],"format":"double"}}}}}},"404":{"description":"Market not found"}}}},"/polymarket/market/trades":{"get":{"tags":["Market"],"summary":"Get market trades","description":"Retrieve trades for one or more markets, with filtering by trader, side, price, amount, and time range","operationId":"get_market_trades","parameters":[{"name":"condition_ids","in":"query","description":"Comma-separated condition IDs (max 20)","required":false,"schema":{"type":"string"}},{"name":"slugs","in":"query","description":"Comma-separated market slugs","required":false,"schema":{"type":"string"}},{"name":"position_ids","in":"query","description":"Comma-separated position IDs","required":false,"schema":{"type":"string"}},{"name":"traders","in":"query","description":"Comma-separated trader addresses (max 25)","required":false,"schema":{"type":"string"}},{"name":"side","in":"query","description":"Trade side: 0 (Buy), 1 (Sell)","required":false,"schema":{"$ref":"#/components/schemas/TradeSide"}},{"name":"outcome","in":"query","description":"Outcome name filter (e.g. Yes, No)","required":false,"schema":{"type":"string"}},{"name":"outcome_index","in":"query","description":"Outcome index: 0 (Yes), 1 (No)","required":false,"schema":{"$ref":"#/components/schemas/OutcomeIndex"}},{"name":"trade_types","in":"query","description":"Comma-separated trade types: OrderFilled, Redemption, Merge, Split, Cancelled, PositionsConverted, OrdersMatched","required":false,"schema":{"type":"string"}},{"name":"min_usd_amount","in":"query","description":"Min USD amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_usd_amount","in":"query","description":"Max USD amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_shares_amount","in":"query","description":"Min shares amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_shares_amount","in":"query","description":"Max shares amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_price","in":"query","description":"Min price (0.0-1.0)","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_price","in":"query","description":"Max price (0.0-1.0)","required":false,"schema":{"type":"number","format":"double"}},{"name":"from","in":"query","description":"Start timestamp (ms)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (ms)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"all","in":"query","description":"Return all-time trades, not just last 30 days (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Results per page (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32","minimum":0}},{"name":"offset","in":"query","description":"Pagination offset (number of results to skip). Takes precedence over pagination_key.","required":false,"schema":{"type":"integer","format":"int32","minimum":0}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key obtained from previous response's pagination.pagination_key","required":false,"schema":{"type":"string"}},{"name":"sort_desc","in":"query","description":"Sort newest first (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Prediction trades matching filters","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TradeEvent"}}}}}}}},"/polymarket/market/volume-chart":{"get":{"tags":["Market"],"summary":"Get market volume chart","description":"Retrieve volume breakdown by YES/NO outcome over time for a prediction market","operationId":"get_market_volume_chart","parameters":[{"name":"condition_id","in":"query","description":"Market condition ID (or use market_slug)","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (alternative to condition_id)","required":false,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Time interval: 1, 5, 15, 30, 60, 240, D, 1D (default: 60)","required":false,"schema":{"$ref":"#/components/schemas/CandlestickResolution"}},{"name":"count_back","in":"query","description":"Number of data points (max: 2500)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"from","in":"query","description":"Start timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Volume breakdown by YES/NO over time","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MarketVolumeDataPoint"}}}}}}}},"/polymarket/market/{condition_id}":{"get":{"tags":["Market"],"summary":"Get market by condition ID","description":"Retrieve a single market by its condition ID with optional nested tags, event, and metrics","operationId":"get_market","parameters":[{"name":"condition_id","in":"path","description":"Market condition ID (0x-prefixed hex)","required":true,"schema":{"type":"string"}},{"name":"include_tags","in":"query","description":"Include tags array (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_event","in":"query","description":"Include event object (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"include_metrics","in":"query","description":"Include all timeframe metrics (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Market with metadata, outcomes, tags, event, and metrics","content":{"application/json":{"schema":{"type":"object","description":"Formatted market response with structured metrics, tags, outcomes, and event","required":["condition_id","status"],"properties":{"condition_id":{"type":"string"},"id":{"type":["string","null"]},"market_slug":{"type":["string","null"]},"question":{"type":["string","null"]},"title":{"type":["string","null"]},"description":{"type":["string","null"]},"image_url":{"type":["string","null"]},"oracle":{"type":["string","null"]},"status":{"type":"string"},"created_time":{"type":["integer","null"],"format":"int64"},"start_time":{"type":["integer","null"],"format":"int64"},"game_start_time":{"type":["integer","null"],"format":"int64"},"closed_time":{"type":["integer","null"],"format":"int64"},"end_time":{"type":["integer","null"],"format":"int64"},"accepting_orders":{"type":["boolean","null"]},"uma_resolution_status":{"type":["string","null"]},"is_neg_risk":{"type":["boolean","null"]},"market_maker_address":{"type":["string","null"]},"creator":{"type":["string","null"]},"category":{"type":["string","null"]},"volume_usd":{"type":["number","null"],"format":"double"},"liquidity_usd":{"type":["number","null"],"format":"double"},"highest_probability":{"type":["number","null"],"format":"double"},"total_holders":{"type":["integer","null"],"format":"int64"},"total_daily_rate":{"type":["number","null"],"format":"double"},"winning_outcome":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/MarketOutcome"}]},"outcomes":{"type":"array","items":{"$ref":"#/components/schemas/MarketOutcome"}},"clob_rewards":{"type":"array","items":{"$ref":"#/components/schemas/ClobReward"}},"tags":{"type":"array","items":{"type":"string"}},"event_slug":{"type":["string","null"]},"resolution_source":{"type":["string","null"]},"metrics":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/SimpleTimeframeMetrics"},"propertyNames":{"type":"string"}},"relevance_score":{"type":["number","null"],"format":"double"}}}}}},"404":{"description":"Market not found"}}}},"/polymarket/order-book":{"get":{"tags":["Order Book"],"summary":"Get order book","description":"Returns the latest CLOB orderbook snapshot for a position, including derived metrics (best bid/ask, mid price, spread, liquidity depth). Data is sourced from the real-time Polymarket WebSocket feed. `bids` and `asks` are arrays of `{\"p\": price, \"s\": size}` objects, sorted best-first.","operationId":"get_order_book","parameters":[{"name":"position_id","in":"query","description":"Token ID (position ID) to query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Latest orderbook snapshot. ts is Unix milliseconds.","content":{"application/json":{"schema":{"type":"object","required":["ts","position_id","condition_id","bids","asks","hash"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"bids":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"asks":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"hash":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}}}}},"400":{"description":"Missing or invalid parameters"}}}},"/polymarket/order-book/history":{"get":{"tags":["Order Book"],"summary":"Get order book history","description":"Paginated history of raw CLOB orderbook snapshots including full bids/asks levels and derived metrics. Default limit 20, max 200. `bids` and `asks` are arrays of `{\"p\": price, \"s\": size}` objects, sorted best-first.","operationId":"get_order_book_history","parameters":[{"name":"position_id","in":"query","description":"Token ID (required if condition_id / market_slug not set)","required":false,"schema":{"type":"string"}},{"name":"condition_id","in":"query","description":"Condition ID — returns history for all positions in this market","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (alternative to condition_id)","required":false,"schema":{"type":"string"}},{"name":"from","in":"query","description":"Start timestamp (Unix milliseconds, inclusive)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (Unix milliseconds, inclusive)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"min_spread","in":"query","description":"Only return snapshots with spread >= this value","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_spread","in":"query","description":"Only return snapshots with spread <= this value","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_liquidity","in":"query","description":"Only return snapshots where total liquidity (bid + ask) >= this value","required":false,"schema":{"type":"number","format":"double"}},{"name":"limit","in":"query","description":"Number of results (default: 20, max: 200)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"pagination_key","in":"query","description":"Cursor from previous response's pagination.pagination_key","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Orderbook snapshot rows, newest first. ts is Unix milliseconds.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","required":["ts","position_id","condition_id","bids","asks","hash"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"bids":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"asks":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"hash":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}}}}}},"400":{"description":"Missing or invalid parameters"}}}},"/polymarket/order-book/market":{"get":{"tags":["Order Book"],"summary":"Get order books for a market","description":"Returns the latest orderbook snapshot for every position (outcome) in a market. Accepts condition_id or market_slug. `bids` and `asks` are arrays of `{\"p\": price, \"s\": size}` objects, sorted best-first.","operationId":"get_market_order_book","parameters":[{"name":"condition_id","in":"query","description":"Condition ID of the market","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (alternative to condition_id)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Latest orderbook snapshot per position. ts is Unix milliseconds.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","required":["ts","position_id","condition_id","bids","asks","hash"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"bids":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"asks":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"hash":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}}}}}},"400":{"description":"Missing or invalid parameters"}}}},"/polymarket/order-book/spread":{"get":{"tags":["Order Book"],"summary":"Get spread history","description":"Lightweight time series of derived orderbook metrics (best bid/ask, mid price, spread, liquidity depth) without raw bids/asks — ideal for charting. Default limit 20, max 200.","operationId":"get_spread_history","parameters":[{"name":"position_id","in":"query","description":"Token ID (required if condition_id / market_slug not set)","required":false,"schema":{"type":"string"}},{"name":"condition_id","in":"query","description":"Condition ID — returns spread history for all positions in this market","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Market slug (alternative to condition_id)","required":false,"schema":{"type":"string"}},{"name":"from","in":"query","description":"Start timestamp (Unix milliseconds, inclusive)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (Unix milliseconds, inclusive)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"min_spread","in":"query","description":"Only return rows with spread >= this value","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_spread","in":"query","description":"Only return rows with spread <= this value","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_liquidity","in":"query","description":"Only return rows where total liquidity (bid + ask) >= this value","required":false,"schema":{"type":"number","format":"double"}},{"name":"limit","in":"query","description":"Number of results (default: 100, max: 1000)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"pagination_key","in":"query","description":"Cursor from previous response's pagination.pagination_key","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Spread time series rows, newest first. ts is Unix milliseconds.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","description":"Lightweight row — derived metrics only, no bids/asks JSONB.","required":["ts","position_id","condition_id"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}}}}}},"400":{"description":"Missing or invalid parameters"}}}},"/polymarket/search":{"get":{"tags":["Search"],"summary":"Search events, markets, and traders","description":"Search across markets, events, and traders. Use `type` to limit which categories are searched. Trader search supports wallet address lookup or name search. Results for each category are independently paginated. Only requested categories are included in the response.","operationId":"search","parameters":[{"name":"q","in":"query","description":"Search query (min 2 characters). Prefix with 0x for exact wallet address lookup.","required":true,"schema":{"type":"string"}},{"name":"type","in":"query","description":"Comma-separated categories to search: events, markets, traders (default: all three, 1 credit per type). Example: type=markets,traders","required":false,"schema":{"type":"string"}},{"name":"include_pnl","in":"query","description":"Include lifetime PnL summary for each trader (default: false, +1 credit)","required":false,"schema":{"type":"boolean"}},{"name":"sort_by","in":"query","description":"Sort field applied to both events and markets (default: volume). Fields marked events-only or markets-only fall back to volume on the other category.","required":false,"schema":{"$ref":"#/components/schemas/SearchSortBy"}},{"name":"sort_dir","in":"query","description":"Sort direction (default: desc)","required":false,"schema":{"$ref":"#/components/schemas/SortDirection"}},{"name":"timeframe","in":"query","description":"Metrics timeframe used for volume/txns/unique_traders sort (default: 24h)","required":false,"schema":{"$ref":"#/components/schemas/MetricsTimeframe"}},{"name":"limit","in":"query","description":"Results limit per category (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"events_pagination_key","in":"query","description":"Cursor for the next page of events, obtained from previous response's events_pagination.pagination_key","required":false,"schema":{"type":"string"}},{"name":"markets_pagination_key","in":"query","description":"Cursor for the next page of markets, obtained from previous response's markets_pagination.pagination_key","required":false,"schema":{"type":"string"}},{"name":"traders_pagination_key","in":"query","description":"Cursor for the next page of traders, obtained from previous response's traders_pagination.pagination_key","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Search results. Only requested categories (via `type`) are included in the response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchResponse"}}}},"400":{"description":"Bad request — q is missing or shorter than 2 characters"}}}},"/polymarket/series":{"get":{"tags":["Series"],"summary":"List or get series","description":"Retrieve series. Use `id` or `series_slug` for single lookup, `series_ids` or `series_slugs` (comma-separated, max 250, mutually exclusive) for multi-lookup, or paginate with `active_only`.","operationId":"get_series_list","parameters":[{"name":"id","in":"query","description":"Single series ID for direct lookup","required":false,"schema":{"type":"string"}},{"name":"series_ids","in":"query","description":"Comma-separated series IDs (max 250). Mutually exclusive with series_slugs.","required":false,"schema":{"type":"string"}},{"name":"series_slugs","in":"query","description":"Comma-separated series slugs (max 250). Mutually exclusive with series_ids.","required":false,"schema":{"type":"string"}},{"name":"active_only","in":"query","description":"Only active series (default: true). Ignored when series_ids or series_slugs are provided.","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor for pagination: id of the last series from the previous page","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Series or list of series","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PolymarketSeries"}}}}},"400":{"description":"series_ids and series_slugs cannot both be provided"}}}},"/polymarket/series/outcomes":{"get":{"tags":["Series"],"summary":"Get series market outcomes","description":"Returns the winning outcome name for each resolved market across all events in a series, keyed by market slug. Useful for checking historical results across recurring series (e.g., btc-updown-5m).","operationId":"get_series_outcomes","parameters":[{"name":"series_slug","in":"query","description":"Series slug (required)","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","description":"Number of resolved markets per page (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key for fetching next page","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Map of market_slug → winning outcome name with pagination metadata","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"},"propertyNames":{"type":"string"}}}}},"400":{"description":"Missing series_slug parameter"}}}},"/polymarket/tags":{"get":{"tags":["Tags"],"summary":"Get tags","description":"Retrieve all available event tags/categories. Supports both cursor-based and offset-based pagination.","operationId":"get_tags","parameters":[{"name":"limit","in":"query","description":"Results limit (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"offset","in":"query","description":"Offset-based pagination (number of results to skip). Takes precedence over pagination_key.","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of all tags","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PolymarketTag"}}}}}}}},"/polymarket/tags/{identifier}":{"get":{"tags":["Tags"],"summary":"Get tag by slug","description":"Retrieve a single tag by its ID or slug","operationId":"get_tag_by_id","parameters":[{"name":"identifier","in":"path","description":"Tag ID or slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Tag details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PolymarketTag"}}}},"404":{"description":"Tag not found"}}}},"/polymarket/trader/global_pnl":{"get":{"tags":["Trader"],"summary":"Get global leaderboard","description":"Retrieve the global PnL leaderboard ranked by profit and loss. Uses cursor-based pagination for efficient traversal of large datasets.","operationId":"get_global_pnl","parameters":[{"name":"timeframe","in":"query","description":"Timeframe: 1d, 7d, 30d, lifetime (default: lifetime)","required":false,"schema":{"$ref":"#/components/schemas/PnlTimeframe"}},{"name":"sort_by","in":"query","description":"Sort: realized_pnl_usd, buys, sells, redemptions, merges, avg_hold_time, markets_traded, events_traded, markets_won, volume_usd, fees, best_trade (default: realized_pnl_usd)","required":false,"schema":{"$ref":"#/components/schemas/GlobalPnlSortBy"}},{"name":"sort_direction","in":"query","description":"Sort direction: asc, desc (default: desc)","required":false,"schema":{"$ref":"#/components/schemas/SortDirection"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 200)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Global PnL leaderboard with trader stats. Response includes `pagination: { has_more, pagination_key }` for cursor-based pagination.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GlobalPnlTrader"}}}}}}}},"/polymarket/trader/pnl/{address}":{"get":{"tags":["Trader"],"summary":"Get trader PnL summary","description":"Retrieve a trader's overall profit and loss summary","operationId":"get_trader_pnl","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"timeframe","in":"query","description":"Timeframe: 1d, 7d, 30d, lifetime (default: lifetime)","required":false,"schema":{"$ref":"#/components/schemas/PnlTimeframe"}}],"responses":{"200":{"description":"Trader's global PnL summary","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TraderPnlSummary"}}}}}}},"/polymarket/trader/pnl/{address}/calendar":{"get":{"tags":["Trader"],"summary":"Get trader PnL calendar","description":"Retrieve raw per-day PnL. Each entry is the realized PnL for that calendar day. Paginate backwards using the pagination key.","operationId":"get_trader_pnl_calendar","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"days","in":"query","description":"Window size in days (default: 30, max: 30)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Pagination key obtained from a previous response to fetch an earlier window","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Daily PnL entries (one per active trading day)","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PnlCandleEntry"}}}}}}}},"/polymarket/trader/pnl/{address}/candles":{"get":{"tags":["Trader"],"summary":"Get trader PnL candles","description":"Retrieve PnL candles for charting a trader's equity curve over time.","operationId":"get_trader_pnl_candles","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Candle resolution (default: 1h)","required":false,"schema":{"$ref":"#/components/schemas/PnlCandleResolution"}},{"name":"timeframe","in":"query","description":"Time range (default: lifetime)","required":false,"schema":{"$ref":"#/components/schemas/PnlCandleTimeframe"}}],"responses":{"200":{"description":"Cumulative PnL candles","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PnlCandleEntry"}}}}}}}},"/polymarket/trader/pnl/{address}/events":{"get":{"tags":["Trader"],"summary":"Get trader event PnL","description":"Retrieve event-level PnL breakdown for a trader","operationId":"get_trader_event_pnl","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"timeframe","in":"query","description":"Timeframe: 1d, 7d, 30d, lifetime (default: lifetime)","required":false,"schema":{"$ref":"#/components/schemas/PnlTimeframe"}},{"name":"sort_by","in":"query","description":"Sort: realized_pnl_usd, total_volume_usd, markets_traded, total_fees (default: realized_pnl_usd)","required":false,"schema":{"$ref":"#/components/schemas/EventPnlSortBy"}},{"name":"sort_direction","in":"query","description":"Sort direction: asc, desc (default: desc)","required":false,"schema":{"$ref":"#/components/schemas/SortDirection"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 200)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"offset","in":"query","description":"Pagination offset (number of results to skip). Takes precedence over pagination_key.","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key obtained from previous response's pagination.pagination_key","required":false,"schema":{"type":"string"}},{"name":"event_slug","in":"query","description":"Filter by event slug","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Event-level PnL entries for this trader","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TraderEventPnlEntry"}}}}}}}},"/polymarket/trader/pnl/{address}/markets":{"get":{"tags":["Trader"],"summary":"Get trader market PnL","description":"Retrieve market-level PnL breakdown for a trader","operationId":"get_trader_market_pnl","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"timeframe","in":"query","description":"Timeframe: 1d, 7d, 30d, lifetime (default: lifetime)","required":false,"schema":{"$ref":"#/components/schemas/PnlTimeframe"}},{"name":"sort_by","in":"query","description":"Sort: realized_pnl_usd, buy_usd, total_buys, total_fees, outcomes_traded (default: realized_pnl_usd)","required":false,"schema":{"$ref":"#/components/schemas/MarketPnlSortBy"}},{"name":"sort_direction","in":"query","description":"Sort direction: asc, desc (default: desc)","required":false,"schema":{"$ref":"#/components/schemas/SortDirection"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 200)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"offset","in":"query","description":"Pagination offset (number of results to skip). Takes precedence over pagination_key.","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key obtained from previous response's pagination.pagination_key","required":false,"schema":{"type":"string"}},{"name":"condition_id","in":"query","description":"Filter by condition ID (or use market_slug)","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Filter by market slug (alternative to condition_id)","required":false,"schema":{"type":"string"}},{"name":"event_slug","in":"query","description":"Filter by event slug","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Market-level PnL entries for this trader","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TraderMarketPnlEntry"}}}}}}}},"/polymarket/trader/pnl/{address}/positions":{"get":{"tags":["Trader"],"summary":"Get trader position PnL","description":"Retrieve per-outcome-token lifetime PnL for a trader from polymarket_accounts. Includes open/closed state, win/loss outcome, redemption payouts, and share quantities. Filter by status and won/lost to segment portfolio views.","operationId":"get_trader_position_pnl","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"status","in":"query","description":"Required. Filter by position status","required":true,"schema":{"$ref":"#/components/schemas/PositionStatus"}},{"name":"won","in":"query","description":"Filter by outcome: true (won), false (lost), only for status=closed","required":false,"schema":{"type":"boolean"}},{"name":"search","in":"query","description":"Search by market title","required":false,"schema":{"type":"string"}},{"name":"sort_by","in":"query","description":"Sort field (default: realized_pnl_usd)","required":false,"schema":{"$ref":"#/components/schemas/PositionPnlSortBy"}},{"name":"sort_direction","in":"query","description":"Sort direction: asc, desc (default: desc)","required":false,"schema":{"$ref":"#/components/schemas/SortDirection"}},{"name":"limit","in":"query","description":"Results limit (default: 10, max: 200)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"offset","in":"query","description":"Pagination offset","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"condition_id","in":"query","description":"Filter by market condition ID (or use market_slug)","required":false,"schema":{"type":"string"}},{"name":"market_slug","in":"query","description":"Filter by market slug (alternative to condition_id)","required":false,"schema":{"type":"string"}},{"name":"position_id","in":"query","description":"Filter by specific outcome token (position ID)","required":false,"schema":{"type":"string"}},{"name":"min_shares","in":"query","description":"Minimum shares balance to include. Status filtering already treats balances below 0.01 shares as dust.","required":false,"schema":{"type":"number","format":"double"}}],"responses":{"200":{"description":"Position-level PnL entries for this trader. Each entry is a specific outcome token with open/closed state, avg_entry_price, avg_exit_price, and redemption info.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TraderOutcomePnlEntry"}}}}}}}},"/polymarket/trader/profile/{address}":{"get":{"tags":["Trader"],"summary":"Get trader overview","description":"Retrieve a trader's profile including stats and trading history summary","operationId":"get_trader_profile","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Trader profile information with username, bio, and badges","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PolymarketUserProfile"}}}}}}},"/polymarket/trader/profiles/batch":{"get":{"tags":["Trader"],"summary":"Get multiple trader profiles","description":"Retrieve profiles for multiple traders in a single request. Returns an array of profiles.","operationId":"get_trader_profiles_batch","parameters":[{"name":"addresses","in":"query","description":"Comma-separated list of trader addresses (max: 20)","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Array of trader profiles","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PolymarketUserProfile"}}}}},"400":{"description":"Invalid request (empty addresses or more than 20)"}}}},"/polymarket/trader/trades/{address}":{"get":{"tags":["Trader"],"summary":"Get trader trades","description":"Retrieve trade history for a specific trader across all markets","operationId":"get_trader_trades","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"condition_ids","in":"query","description":"Comma-separated condition IDs (max 20)","required":false,"schema":{"type":"string"}},{"name":"slugs","in":"query","description":"Comma-separated market slugs","required":false,"schema":{"type":"string"}},{"name":"position_ids","in":"query","description":"Comma-separated position IDs","required":false,"schema":{"type":"string"}},{"name":"side","in":"query","description":"Trade side: 0 (Buy), 1 (Sell)","required":false,"schema":{"$ref":"#/components/schemas/TradeSide"}},{"name":"outcome","in":"query","description":"Outcome name filter (e.g. Yes, No)","required":false,"schema":{"type":"string"}},{"name":"outcome_index","in":"query","description":"Outcome index: 0 (Yes), 1 (No)","required":false,"schema":{"$ref":"#/components/schemas/OutcomeIndex"}},{"name":"trade_types","in":"query","description":"Comma-separated trade types: OrderFilled, Redemption, Merge, Split, Cancelled, PositionsConverted, OrdersMatched","required":false,"schema":{"type":"string"}},{"name":"min_usd_amount","in":"query","description":"Min USD amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_usd_amount","in":"query","description":"Max USD amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_shares_amount","in":"query","description":"Min shares amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_shares_amount","in":"query","description":"Max shares amount","required":false,"schema":{"type":"number","format":"double"}},{"name":"min_price","in":"query","description":"Min price (0.0-1.0)","required":false,"schema":{"type":"number","format":"double"}},{"name":"max_price","in":"query","description":"Max price (0.0-1.0)","required":false,"schema":{"type":"number","format":"double"}},{"name":"from","in":"query","description":"Start timestamp (ms)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (ms)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"all","in":"query","description":"Return all-time trades, not just last 30 days (default: false)","required":false,"schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"Results per page (default: 10, max: 250)","required":false,"schema":{"type":"integer","format":"int32","minimum":0}},{"name":"offset","in":"query","description":"Pagination offset (number of results to skip). Takes precedence over pagination_key.","required":false,"schema":{"type":"integer","format":"int32","minimum":0}},{"name":"pagination_key","in":"query","description":"Cursor-based pagination key obtained from previous response's pagination.pagination_key","required":false,"schema":{"type":"string"}},{"name":"sort_desc","in":"query","description":"Sort newest first (default: true)","required":false,"schema":{"type":"boolean"}},{"name":"ai","in":"query","description":"Return truncated response optimized for AI consumers (default: false)","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Trader's trade history with advanced filtering (same as /market/trades but filtered by trader)","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TradeEvent"}}}}}}}},"/polymarket/trader/volume-chart/{address}":{"get":{"tags":["Trader"],"summary":"Get trader volume chart","description":"Retrieve volume breakdown by buy/sell over time for a specific trader","operationId":"get_trader_volume_chart","parameters":[{"name":"address","in":"path","description":"Trader wallet address","required":true,"schema":{"type":"string"}},{"name":"resolution","in":"query","description":"Time interval: 1, 5, 15, 30, 60, 240, D, 1D (default: 60)","required":false,"schema":{"$ref":"#/components/schemas/CandlestickResolution"}},{"name":"count_back","in":"query","description":"Number of data points (max: 2500)","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"from","in":"query","description":"Start timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}},{"name":"to","in":"query","description":"End timestamp (Unix seconds)","required":false,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"Trader volume with buy/sell breakdown over time","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TraderVolumeDataPoint"}}}}}}}}},"components":{"schemas":{"ApprovalTrade":{"type":"object","description":"Output payload for ERC1155 setApprovalForAll events.","required":["id","hash","trader","operator","approved","exchange"],"properties":{"id":{"type":"string"},"hash":{"type":"string"},"block":{"type":["integer","null"],"format":"int64","minimum":0},"confirmed_at":{"type":["integer","null"],"format":"int64","minimum":0},"received_at":{"type":["integer","null"],"format":"int64","minimum":0},"log_index":{"type":["integer","null"],"format":"int64","minimum":0},"block_index":{"type":["integer","null"],"format":"int64","minimum":0},"trader":{"$ref":"#/components/schemas/TraderInfo"},"operator":{"type":"string"},"approved":{"type":"boolean"},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"slug":{"type":["string","null"]},"event_slug":{"type":["string","null"]},"exchange":{"$ref":"#/components/schemas/PolymarketExchange"}}},"AssertionDisputedEvent":{"type":"object","description":"V3 UMA OOv3: an assertion was disputed.","required":["id","hash","oracle_contract","assertion_id","caller","disputer"],"properties":{"id":{"type":"string"},"hash":{"type":"string"},"block":{"type":["integer","null"],"format":"int64","minimum":0},"confirmed_at":{"type":["integer","null"],"format":"int64","minimum":0},"received_at":{"type":["integer","null"],"format":"int64","minimum":0},"log_index":{"type":["integer","null"],"format":"int64","minimum":0},"block_index":{"type":["integer","null"],"format":"int64","minimum":0},"oracle_contract":{"type":"string"},"assertion_id":{"type":"string"},"caller":{"type":"string"},"disputer":{"type":"string"},"condition_id":{"type":["string","null"]},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"slug":{"type":["string","null"]},"event_slug":{"type":["string","null"]}}},"AssertionMadeEvent":{"type":"object","description":"V3 UMA OOv3: a new assertion (resolution proposal) was made.","required":["id","hash","oracle_contract","assertion_id","domain_id","claim","asserter","callback_recipient","escalation_manager","caller","expiration_time","currency","bond","identifier"],"properties":{"id":{"type":"string"},"hash":{"type":"string"},"block":{"type":["integer","null"],"format":"int64","minimum":0},"confirmed_at":{"type":["integer","null"],"format":"int64","minimum":0},"received_at":{"type":["integer","null"],"format":"int64","minimum":0},"log_index":{"type":["integer","null"],"format":"int64","minimum":0},"block_index":{"type":["integer","null"],"format":"int64","minimum":0},"oracle_contract":{"type":"string"},"assertion_id":{"type":"string"},"domain_id":{"type":"string"},"claim":{"type":"string"},"asserter":{"type":"string"},"callback_recipient":{"type":"string"},"escalation_manager":{"type":"string"},"caller":{"type":"string"},"expiration_time":{"type":"integer","format":"int64","minimum":0},"currency":{"type":"string"},"bond":{"type":"string"},"identifier":{"type":"string"},"condition_id":{"type":["string","null"]},"proposed_outcome":{"type":["string","null"]},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"slug":{"type":["string","null"]},"event_slug":{"type":["string","null"]}}},"AssertionSettledEvent":{"type":"object","description":"V3 UMA OOv3: an assertion liveness period expired and was settled.","required":["id","hash","oracle_contract","assertion_id","bond_recipient","disputed","settlement_resolution","settle_caller"],"properties":{"id":{"type":"string"},"hash":{"type":"string"},"block":{"type":["integer","null"],"format":"int64","minimum":0},"confirmed_at":{"type":["integer","null"],"format":"int64","minimum":0},"received_at":{"type":["integer","null"],"format":"int64","minimum":0},"log_index":{"type":["integer","null"],"format":"int64","minimum":0},"block_index":{"type":["integer","null"],"format":"int64","minimum":0},"oracle_contract":{"type":"string"},"assertion_id":{"type":"string"},"bond_recipient":{"type":"string"},"disputed":{"type":"boolean"},"settlement_resolution":{"type":"boolean"},"settle_caller":{"type":"string"},"condition_id":{"type":["string","null"]},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"slug":{"type":["string","null"]},"event_slug":{"type":["string","null"]}}},"AssetPriceHistoryRow":{"type":"object","description":"A single asset price history record from the `asset_price_history` table.","required":["asset_symbol","asset_open_price","asset_close_price","variant","start_time","end_time"],"properties":{"asset_symbol":{"type":"string"},"asset_open_price":{"type":"number","format":"double","description":"Opening price at start_time (cast to f64 from NUMERIC in query)"},"asset_close_price":{"type":"number","format":"double","description":"Closing price at end_time (cast to f64 from NUMERIC in query)"},"price_change_percentage":{"type":["number","null"],"format":"double"},"outcome":{"type":["string","null"],"description":"Generated column: \"up\" if close > open, \"down\" if close ≤ open, null if no close yet"},"variant":{"type":"string","description":"Time window: \"5m\", \"15m\", \"1h\", \"1d\""},"start_time":{"type":"integer","format":"int64","description":"Window start timestamp (seconds since epoch)"},"end_time":{"type":"integer","format":"int64","description":"Window end timestamp (seconds since epoch)"}}},"AssetSymbol":{"type":"string","enum":["BTC","ETH","XRP","SOL","DOGE","BNB","HYPE"]},"AssetVariant":{"type":"string","enum":["5m","15m","1h","4h","1d"]},"BondMarket":{"type":"object","required":["condition_id","question","market_slug","end_time","best_outcome_index","return_pct","apy","outcomes"],"properties":{"condition_id":{"type":"string"},"title":{"type":["string","null"]},"question":{"type":"string"},"market_slug":{"type":"string"},"event_slug":{"type":["string","null"]},"image_url":{"type":["string","null"]},"end_time":{"type":"integer","format":"int64"},"best_outcome_index":{"type":"integer","format":"int32","minimum":0},"return_pct":{"type":"number","format":"double"},"apy":{"type":"number","format":"double"},"volume_24h":{"type":["number","null"],"format":"double"},"outcomes":{"type":"array","items":{"$ref":"#/components/schemas/BondOutcome"}}}},"BondOutcome":{"type":"object","required":["name","index","position_id","price"],"properties":{"name":{"type":"string"},"index":{"type":"integer","format":"int32"},"position_id":{"type":"string"},"price":{"type":"number","format":"double"}}},"CancelledTrade":{"type":"object","description":"Output payload for Cancelled orders.","required":["id","hash","exchange"],"properties":{"id":{"type":"string"},"hash":{"type":"string"},"block":{"type":["integer","null"],"format":"int64","minimum":0},"confirmed_at":{"type":["integer","null"],"format":"int64","minimum":0},"received_at":{"type":["integer","null"],"format":"int64","minimum":0},"log_index":{"type":["integer","null"],"format":"int64","minimum":0},"block_index":{"type":["integer","null"],"format":"int64","minimum":0},"order_hash":{"type":["string","null"]},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"slug":{"type":["string","null"]},"event_slug":{"type":["string","null"]},"exchange":{"$ref":"#/components/schemas/PolymarketExchange"}}},"CandlestickResolution":{"type":"string","enum":["1","5","15","30","60","240","D","1D"]},"ChartResolution":{"type":"string","enum":["1H","6H","1D","1W","1M","ALL"]},"ClobReward":{"type":"object","description":"CLOB reward (public API format)","required":["id","condition_id"],"properties":{"id":{"type":"string"},"condition_id":{"type":"string"},"asset_address":{"type":["string","null"]},"rewards_amount":{"type":["number","null"],"format":"double"},"rewards_daily_rate":{"type":["number","null"],"format":"double"},"start_date":{"type":["string","null"]},"end_date":{"type":["string","null"]},"rewards_max_spread":{"type":["number","null"],"format":"double"},"rewards_min_size":{"type":["number","null"],"format":"double"},"native_daily_rate":{"type":["number","null"],"format":"double"},"sponsored_daily_rate":{"type":["number","null"],"format":"double"},"total_daily_rate":{"type":["number","null"],"format":"double"},"sponsors_count":{"type":["integer","null"],"format":"int32"}}},"ConditionMetricsResponse":{"type":"object","description":"Response type for condition metrics query","required":["condition_id","timeframe","volume_usd","fees","txns","unique_traders"],"properties":{"condition_id":{"type":"string"},"timeframe":{"type":"string"},"volume_usd":{"type":"number","format":"double"},"fees":{"type":"number","format":"double"},"txns":{"type":"integer","format":"int32"},"unique_traders":{"type":"integer","format":"int32"}}},"ConditionOrderbookRow":{"type":"object","required":["ts","position_id","condition_id","bids","asks","hash"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"bids":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"asks":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"hash":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}},"ConditionResolutionEvent":{"type":"object","description":"CTF ConditionResolution: positions become redeemable on the Conditional Tokens contract.","required":["id","hash","oracle_contract","condition_id","oracle"],"properties":{"id":{"type":"string"},"hash":{"type":"string"},"block":{"type":["integer","null"],"format":"int64","minimum":0},"confirmed_at":{"type":["integer","null"],"format":"int64","minimum":0},"received_at":{"type":["integer","null"],"format":"int64","minimum":0},"log_index":{"type":["integer","null"],"format":"int64","minimum":0},"block_index":{"type":["integer","null"],"format":"int64","minimum":0},"oracle_contract":{"type":"string"},"condition_id":{"type":"string"},"oracle":{"type":"string"},"proposed_outcome":{"type":["string","null"]},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"slug":{"type":["string","null"]},"event_slug":{"type":["string","null"]}}},"EventMarket":{"type":"object","description":"Enriched market data for event API responses","properties":{"condition_id":{"type":"string","default":""},"id":{"type":["string","null"],"default":null},"title":{"type":["string","null"],"default":null},"question":{"type":"string","default":""},"market_slug":{"type":"string","default":""},"status":{"type":"string","default":""},"created_time":{"type":["integer","null"],"format":"int64","default":null},"end_time":{"type":["integer","null"],"format":"int64","default":null},"volume":{"type":["number","null"],"format":"double","default":null},"liquidity_usd":{"type":["number","null"],"format":"double","default":null},"volume_24hr":{"type":["number","null"],"format":"double","default":null},"image_url":{"type":["string","null"],"default":null},"market_maker_address":{"type":["string","null"],"default":null},"creator":{"type":["string","null"],"default":null},"category":{"type":["string","null"],"default":null},"accepting_orders":{"type":["boolean","null"],"default":null},"uma_resolution_status":{"type":["string","null"],"default":null},"clob_rewards":{"type":"array","items":{"$ref":"#/components/schemas/ClobReward"},"default":[]},"outcomes":{"type":"array","items":{"$ref":"#/components/schemas/EventMarketOutcome"},"default":[]},"winning_outcome":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/EventMarketOutcome"}],"default":null}}},"EventMarketChartDataPoint":{"type":"object","required":["v","t"],"properties":{"v":{"type":"number","format":"double"},"t":{"type":"integer","format":"int64","minimum":0}}},"EventMarketChartOutcome":{"type":"object","required":["condition_id","market_slug","question","title","data"],"properties":{"condition_id":{"type":"string"},"market_slug":{"type":"string"},"question":{"type":"string"},"title":{"type":"string"},"data":{"type":"array","items":{"$ref":"#/components/schemas/EventMarketChartDataPoint"}}}},"EventMarketOutcome":{"type":"object","description":"Market outcome for event API responses","required":["name"],"properties":{"name":{"type":"string"},"price":{"type":["number","null"],"format":"double"},"position_id":{"type":["string","null"]},"outcome_index":{"type":["integer","null"],"format":"int32"}}},"EventMetricsResponse":{"type":"object","description":"Response type for event metrics query","required":["event_slug","timeframe","volume_usd","fees","txns","unique_traders"],"properties":{"event_slug":{"type":"string"},"timeframe":{"type":"string"},"volume_usd":{"type":"number","format":"double"},"fees":{"type":"number","format":"double"},"txns":{"type":"integer","format":"int32"},"unique_traders":{"type":"integer","format":"int32"}}},"EventPnlSortBy":{"type":"string","enum":["realized_pnl_usd","total_volume_usd","markets_traded","total_fees","realized_pnl_pct"]},"EventSortBy":{"type":"string","enum":["volume","txns","unique_traders","title","creation_date","start_date","end_date","relevance"]},"GlobalPnlSortBy":{"type":"string","enum":["realized_pnl_usd","buys","sells","redemptions","merges","avg_hold_time","markets_traded","events_traded","markets_won","volume_usd","fees","best_trade"]},"GlobalPnlTrader":{"type":"object","description":"Individual trader entry in the global PnL leaderboard","required":["trader"],"properties":{"trader":{"$ref":"#/components/schemas/TraderInfo"},"realized_pnl_usd":{"type":["number","null"],"format":"double"},"events_traded":{"type":["integer","null"],"format":"int64"},"markets_traded":{"type":["integer","null"],"format":"int64"},"markets_won":{"type":["integer","null"],"format":"int64"},"markets_lost":{"type":["integer","null"],"format":"int64"},"market_win_rate_pct":{"type":["number","null"],"format":"double"},"total_volume_usd":{"type":["number","null"],"format":"double"},"buy_volume_usd":{"type":["number","null"],"format":"double"},"sell_volume_usd":{"type":["number","null"],"format":"double"},"redemption_volume_usd":{"type":["number","null"],"format":"double"},"merge_volume_usd":{"type":["number","null"],"format":"double"},"total_buys":{"type":["integer","null"],"format":"int64"},"total_sells":{"type":["integer","null"],"format":"int64"},"total_redemptions":{"type":["integer","null"],"format":"int64"},"total_merges":{"type":["integer","null"],"format":"int64"},"total_trades":{"type":["integer","null"],"format":"int64"},"total_fees":{"type":["number","null"],"format":"double"},"avg_pnl_per_market":{"type":["number","null"],"format":"double"},"avg_pnl_per_trade":{"type":["number","null"],"format":"double"},"avg_hold_time_seconds":{"type":["number","null"],"format":"double"},"best_trade_pnl_usd":{"type":["number","null"],"format":"double"},"best_trade_condition_id":{"type":["string","null"]},"first_trade_at":{"type":["integer","null"],"format":"int64"},"last_trade_at":{"type":["integer","null"],"format":"int64"}}},"Holder":{"type":"object","description":"Individual holder data","required":["trader","shares"],"properties":{"trader":{"$ref":"#/components/schemas/Trader","description":"Trader profile information"},"shares":{"type":"string","description":"Position shares held (raw balance as string for precision)"},"shares_usd":{"type":["string","null"],"description":"USD value of shares (shares * latest price)"},"usd_balance":{"type":["string","null"],"description":"USD balance of wallet (USDe on Polygon)"},"pnl":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/HolderPnl","description":"Holder-level PnL, included only when `include_pnl=true`"}]}}},"HolderHistoryCandle":{"type":"object","description":"Holder statistics data point (single time bucket)","required":["t"],"properties":{"t":{"type":"integer","format":"int64"},"h":{"type":["integer","null"],"format":"int64"}}},"HolderPnl":{"type":"object","description":"Holder-level PnL data, included when `include_pnl=true`","properties":{"avg_entry_price":{"type":["number","null"],"format":"double"},"total_cost_usd":{"type":["string","null"]},"unrealized_pnl_usd":{"type":["string","null"]},"realized_sell_pnl_usd":{"type":["string","null"]},"avg_exit_price":{"type":["number","null"],"format":"double"},"buy_usd":{"type":["number","null"],"format":"double"},"sell_usd":{"type":["number","null"],"format":"double"},"total_buys":{"type":["integer","null"],"format":"int64"},"total_sells":{"type":["integer","null"],"format":"int64"},"total_fees":{"type":["number","null"],"format":"double"},"first_trade_at":{"type":["integer","null"],"format":"int64"},"last_trade_at":{"type":["integer","null"],"format":"int64"}}},"MarketHoldersResponse":{"type":"object","description":"Response for market (condition_id) holders endpoint","required":["condition_id","total_holders","outcomes"],"properties":{"condition_id":{"type":"string","description":"Market condition ID"},"question":{"type":["string","null"],"description":"Market question/title"},"slug":{"type":["string","null"],"description":"Market slug"},"total_holders":{"type":"integer","format":"int64","description":"Total unique holders across all outcomes (from holder_stats)"},"outcomes":{"type":"array","items":{"$ref":"#/components/schemas/OutcomeHolders"},"description":"Holders grouped by outcome"}}},"MarketMetadataOutcome":{"type":"object","description":"Market outcome with timeframe metrics (websocket API format)","required":["token_id","outcome"],"properties":{"token_id":{"type":"string"},"outcome":{"type":"string"},"last_price":{"type":["number","null"],"format":"double"},"last_probability":{"type":["number","null"],"format":"double"},"metrics":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/OutcomeTimeframeMetrics"},"propertyNames":{"type":"string"}}}},"MarketOutcome":{"type":"object","description":"Outcome for market API responses","properties":{"name":{"type":"string","default":""},"price":{"type":["number","null"],"format":"double","default":null},"position_id":{"type":["string","null"],"default":null},"outcome_index":{"type":["integer","null"],"format":"int32","default":null}}},"MarketPnlSortBy":{"type":"string","enum":["realized_pnl_usd","buy_usd","total_buys","total_fees","outcomes_traded","realized_pnl_pct"]},"MarketResponse":{"type":"object","description":"Formatted market response with structured metrics, tags, outcomes, and event","required":["condition_id","status"],"properties":{"condition_id":{"type":"string"},"id":{"type":["string","null"]},"market_slug":{"type":["string","null"]},"question":{"type":["string","null"]},"title":{"type":["string","null"]},"description":{"type":["string","null"]},"image_url":{"type":["string","null"]},"oracle":{"type":["string","null"]},"status":{"type":"string"},"created_time":{"type":["integer","null"],"format":"int64"},"start_time":{"type":["integer","null"],"format":"int64"},"game_start_time":{"type":["integer","null"],"format":"int64"},"closed_time":{"type":["integer","null"],"format":"int64"},"end_time":{"type":["integer","null"],"format":"int64"},"accepting_orders":{"type":["boolean","null"]},"uma_resolution_status":{"type":["string","null"]},"is_neg_risk":{"type":["boolean","null"]},"market_maker_address":{"type":["string","null"]},"creator":{"type":["string","null"]},"category":{"type":["string","null"]},"volume_usd":{"type":["number","null"],"format":"double"},"liquidity_usd":{"type":["number","null"],"format":"double"},"highest_probability":{"type":["number","null"],"format":"double"},"total_holders":{"type":["integer","null"],"format":"int64"},"total_daily_rate":{"type":["number","null"],"format":"double"},"winning_outcome":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/MarketOutcome"}]},"outcomes":{"type":"array","items":{"$ref":"#/components/schemas/MarketOutcome"}},"clob_rewards":{"type":"array","items":{"$ref":"#/components/schemas/ClobReward"}},"tags":{"type":"array","items":{"type":"string"}},"event_slug":{"type":["string","null"]},"resolution_source":{"type":["string","null"]},"metrics":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/SimpleTimeframeMetrics"},"propertyNames":{"type":"string"}},"relevance_score":{"type":["number","null"],"format":"double"}}},"MarketSortBy":{"type":"string","enum":["volume","txns","unique_traders","liquidity","holders","total_daily_rate","end_time","start_time","created_time","relevance"]},"MarketStatus":{"type":"string","enum":["open","closed","all"]},"MarketVolumeChartResponse":{"type":"object","required":["volumes","has_more"],"properties":{"volumes":{"type":"array","items":{"$ref":"#/components/schemas/MarketVolumeDataPoint"}},"has_more":{"type":"boolean"}}},"MarketVolumeDataPoint":{"type":"object","required":["t","v","yv","nv","tc","ytc","ntc"],"properties":{"t":{"type":"integer","format":"int64"},"v":{"type":"number","format":"double"},"yv":{"type":"number","format":"double"},"nv":{"type":"number","format":"double"},"tc":{"type":"integer","format":"int32"},"ytc":{"type":"integer","format":"int32"},"ntc":{"type":"integer","format":"int32"}}},"MergeTrade":{"type":"object","description":"Output payload for Merge trades (burn outcome tokens → receive collateral).","required":["id","hash","trader","usd_amount","exchange"],"properties":{"id":{"type":"string"},"hash":{"type":"string"},"block":{"type":["integer","null"],"format":"int64","minimum":0},"confirmed_at":{"type":["integer","null"],"format":"int64","minimum":0},"received_at":{"type":["integer","null"],"format":"int64","minimum":0},"log_index":{"type":["integer","null"],"format":"int64","minimum":0},"block_index":{"type":["integer","null"],"format":"int64","minimum":0},"trader":{"$ref":"#/components/schemas/TraderInfo"},"condition_id":{"type":["string","null"]},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"slug":{"type":["string","null"]},"event_slug":{"type":["string","null"]},"usd_amount":{"type":"number","format":"double"},"position_details":{"type":"array","items":{"$ref":"#/components/schemas/PositionDetail"},"description":"Per-position burn amounts"},"exchange":{"$ref":"#/components/schemas/PolymarketExchange"}}},"MetricsTimeframe":{"type":"string","enum":["1m","5m","30m","1h","6h","24h","7d","30d"]},"NegRiskOutcomeReportedEvent":{"type":"object","description":"NegRisk Adapter: outcome reported for a neg-risk market question.","required":["id","hash","oracle_contract","condition_id"],"properties":{"id":{"type":"string"},"hash":{"type":"string"},"block":{"type":["integer","null"],"format":"int64","minimum":0},"confirmed_at":{"type":["integer","null"],"format":"int64","minimum":0},"received_at":{"type":["integer","null"],"format":"int64","minimum":0},"log_index":{"type":["integer","null"],"format":"int64","minimum":0},"block_index":{"type":["integer","null"],"format":"int64","minimum":0},"oracle_contract":{"type":"string"},"condition_id":{"type":"string"},"proposed_outcome":{"type":["string","null"]},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"slug":{"type":["string","null"]},"event_slug":{"type":["string","null"]}}},"OrderFilledTrade":{"type":"object","description":"Output payload for OrderFilled and OrdersMatched trades (actual buy/sell).","required":["id","hash","trader","side","position_id","usd_amount","shares_amount","price","exchange"],"properties":{"id":{"type":"string"},"hash":{"type":"string"},"block":{"type":["integer","null"],"format":"int64","minimum":0},"confirmed_at":{"type":["integer","null"],"format":"int64","minimum":0},"received_at":{"type":["integer","null"],"format":"int64","minimum":0},"log_index":{"type":["integer","null"],"format":"int64","minimum":0},"block_index":{"type":["integer","null"],"format":"int64","minimum":0},"order_hash":{"type":["string","null"]},"trader":{"$ref":"#/components/schemas/TraderInfo"},"taker":{"type":["string","null"]},"side":{"type":"string"},"condition_id":{"type":["string","null"]},"position_id":{"type":"string"},"outcome":{"type":["string","null"]},"outcome_index":{"type":["integer","null"],"format":"int32","minimum":0},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"slug":{"type":["string","null"]},"event_slug":{"type":["string","null"]},"usd_amount":{"type":"number","format":"double"},"shares_amount":{"type":"number","format":"double"},"price":{"type":"number","format":"double"},"probability":{"type":["number","null"],"format":"double"},"fee":{"type":["number","null"],"format":"double"},"fee_shares":{"type":["number","null"],"format":"double"},"fee_pct":{"type":["number","null"],"format":"double"},"exchange":{"$ref":"#/components/schemas/PolymarketExchange"}}},"OrderbookHistoryRow":{"type":"object","required":["ts","position_id","condition_id","bids","asks","hash"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"bids":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"asks":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"hash":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}},"OrderbookLevel":{"type":"object","description":"A single price level in a bids/asks array.","required":["p","s"],"properties":{"p":{"type":"string","description":"Price as a decimal string"},"s":{"type":"string","description":"Size as a decimal string"}}},"OrderbookSnapshotRow":{"type":"object","required":["ts","position_id","condition_id","bids","asks","hash"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"bids":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"asks":{"type":"array","items":{"$ref":"#/components/schemas/OrderbookLevel"}},"hash":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}},"OutcomeHolders":{"type":"object","description":"Holder data grouped by outcome for market-level queries","required":["outcome_index","outcome_name","position_id","total_holders","holders"],"properties":{"outcome_index":{"type":"integer","format":"int32","description":"Outcome index (0, 1, etc.)"},"outcome_name":{"type":"string","description":"Outcome name (Yes, No, etc.)"},"position_id":{"type":"string","description":"Position ID for this outcome"},"price":{"type":["number","null"],"format":"double","description":"Current price/probability"},"total_holders":{"type":"integer","format":"int64","description":"Total holders count from holder_stats"},"holders":{"type":"array","items":{"$ref":"#/components/schemas/Holder"},"description":"Top holders for this outcome"}}},"OutcomeIndex":{"type":"string","enum":["0","1"]},"OutcomeTimeframeMetrics":{"type":"object","properties":{"volume":{"type":"number","format":"double","default":0.0},"buy_volume":{"type":"number","format":"double","default":0.0},"sell_volume":{"type":"number","format":"double","default":0.0},"txns":{"type":"integer","format":"int32","default":0},"buys":{"type":"integer","format":"int32","default":0},"sells":{"type":"integer","format":"int32","default":0},"price_open":{"type":["number","null"],"format":"double","default":null},"price_close":{"type":["number","null"],"format":"double","default":null},"price_high":{"type":["number","null"],"format":"double","default":null},"price_low":{"type":["number","null"],"format":"double","default":null},"probability_open":{"type":["number","null"],"format":"double","default":null},"probability_close":{"type":["number","null"],"format":"double","default":null},"probability_high":{"type":["number","null"],"format":"double","default":null},"probability_low":{"type":["number","null"],"format":"double","default":null},"price_change_percent":{"type":["number","null"],"format":"double","default":null}}},"PaginationMeta":{"type":"object","description":"Pagination metadata to include in API responses","required":["has_more"],"properties":{"has_more":{"type":"boolean","description":"Whether there are more results available"},"pagination_key":{"type":["string","null"],"description":"Pagination key for the next page (if has_more is true)"}}},"PnlCandleEntry":{"type":"object","description":"A single PnL candle entry","required":["t","pnl"],"properties":{"t":{"type":"integer","format":"int64","description":"Timestamp in epoch seconds (start of bucket window)"},"pnl":{"type":"number","format":"double","description":"Realized PnL in this bucket (USD)"}}},"PnlCandleResolution":{"type":"string","enum":["1m","1h","1d"]},"PnlCandleTimeframe":{"type":"string","enum":["1d","7d","30d","lifetime"]},"PnlTimeframe":{"type":"string","enum":["1d","7d","30d","lifetime"]},"PolymarketEvent":{"type":"object","description":"A Polymarket event from the Gamma API","properties":{"id":{"type":"string","default":""},"event_slug":{"type":["string","null"],"default":null},"title":{"type":["string","null"],"default":null},"ticker":{"type":["string","null"],"default":null},"description":{"type":["string","null"],"default":null},"resolution_source":{"type":["string","null"],"default":null},"category":{"type":["string","null"],"default":null},"image_url":{"type":["string","null"],"default":null},"market_count":{"type":"integer","format":"int32","default":0},"created_time":{"type":["integer","null"],"format":"int64","default":null},"closed_time":{"type":["integer","null"],"format":"int64","default":null},"start_time":{"type":["integer","null"],"format":"int64","default":null},"end_time":{"type":["integer","null"],"format":"int64","default":null},"neg_risk":{"type":"boolean","default":false},"neg_risk_market_id":{"type":["string","null"],"default":null},"game_status":{"type":["string","null"],"default":null},"show_market_images":{"type":"boolean","default":false},"status":{"type":["string","null"],"description":"Event status: \"open\" or \"closed\"","default":null},"metrics":{"type":"object","default":{},"additionalProperties":{"$ref":"#/components/schemas/SimpleTimeframeMetrics"},"propertyNames":{"type":"string"}},"tags":{"type":"array","items":{"$ref":"#/components/schemas/PolymarketTag"},"default":[]},"markets":{"type":"array","items":{"$ref":"#/components/schemas/EventMarket"},"default":[]},"series":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PolymarketSeries"}],"default":null}}},"PolymarketExchange":{"type":"string","description":"Polymarket exchange contract types","enum":["CTFExchange","NegRiskExchange","ConditionalTokens","NegRiskAdapter","Unknown"]},"PolymarketSeries":{"type":"object","description":"A Polymarket series from the Gamma API\nSeries are parent groupings above events (e.g., \"NBA Season 2024-25\")","properties":{"id":{"type":"string","default":""},"slug":{"type":["string","null"],"default":null},"ticker":{"type":["string","null"],"default":null},"title":{"type":["string","null"],"default":null},"description":{"type":["string","null"],"default":null},"series_type":{"type":["string","null"],"default":null},"recurrence":{"type":["string","null"],"default":null},"layout":{"type":["string","null"],"default":null},"image_url":{"type":["string","null"],"default":null},"icon_url":{"type":["string","null"],"default":null},"active":{"type":"boolean","default":false},"closed":{"type":"boolean","default":false},"archived":{"type":"boolean","default":false},"featured":{"type":"boolean","default":false},"restricted":{"type":"boolean","default":false},"pyth_token_id":{"type":["string","null"],"default":null},"cg_asset_name":{"type":["string","null"],"default":null},"start_date":{"type":["integer","null"],"format":"int64","default":null},"event_count":{"type":"integer","format":"int32","default":0}}},"PolymarketTag":{"type":"object","description":"A Polymarket tag from the Gamma API","properties":{"id":{"type":"string","default":""},"label":{"type":"string","default":""},"slug":{"type":["string","null"],"default":null}}},"PolymarketUserProfile":{"type":"object","description":"Polymarket user profile (public API format)","required":["proxy_wallet","display_username_public","verified_badge","is_creator","is_mod"],"properties":{"proxy_wallet":{"type":"string"},"name":{"type":["string","null"]},"pseudonym":{"type":["string","null"]},"bio":{"type":["string","null"]},"profile_image":{"type":["string","null"]},"x_username":{"type":["string","null"]},"display_username_public":{"type":"boolean"},"verified_badge":{"type":"boolean"},"user_id":{"type":["string","null"]},"is_creator":{"type":"boolean"},"is_mod":{"type":"boolean"},"created_at":{"type":["string","null"]}}},"PositionChartDataPoint":{"type":"object","required":["v","t"],"properties":{"v":{"type":"number","format":"double"},"t":{"type":"integer","format":"int64","minimum":0}}},"PositionChartOutcome":{"type":"object","required":["position_id","name","outcome_index","data"],"properties":{"position_id":{"type":"string"},"name":{"type":"string"},"outcome_index":{"type":"integer","format":"int32"},"data":{"type":"array","items":{"$ref":"#/components/schemas/PositionChartDataPoint"}}}},"PositionDetail":{"type":"object","description":"Per-position detail for Split/Merge/Redemption trades.","required":["position_id","outcome_index","amount"],"properties":{"position_id":{"type":"string","description":"ERC1155 position ID"},"outcome_index":{"type":"integer","format":"int32","description":"Outcome index (0 = Yes, 1 = No for binary)","minimum":0},"outcome":{"type":["string","null"],"description":"Outcome name (e.g. \"Yes\", \"No\") — enriched from market metadata"},"amount":{"type":"string","description":"Amount of shares created/burned/redeemed for this position"}}},"PositionHoldersResponse":{"type":"object","description":"Response for position (position_id) holders endpoint","required":["position_id","total_holders","holders"],"properties":{"position_id":{"type":"string","description":"Position ID (ERC1155 token ID)"},"condition_id":{"type":["string","null"],"description":"Condition ID this position belongs to"},"outcome_name":{"type":["string","null"],"description":"Outcome name"},"outcome_index":{"type":["integer","null"],"format":"int32","description":"Outcome index"},"price":{"type":["number","null"],"format":"double","description":"Current price"},"total_holders":{"type":"integer","format":"int64","description":"Total holders count from holder_stats"},"holders":{"type":"array","items":{"$ref":"#/components/schemas/Holder"},"description":"Top holders"}}},"PositionMetricsResponse":{"type":"object","description":"Response type for position metrics query","required":["position_id","condition_id","timeframe","volume_usd","buy_volume_usd","sell_volume_usd","fees","txns","buys","sells","unique_traders","price_open","price_high","price_low","price_close"],"properties":{"position_id":{"type":"string"},"condition_id":{"type":"string"},"timeframe":{"type":"string"},"volume_usd":{"type":"number","format":"double"},"buy_volume_usd":{"type":"number","format":"double"},"sell_volume_usd":{"type":"number","format":"double"},"fees":{"type":"number","format":"double"},"txns":{"type":"integer","format":"int32"},"buys":{"type":"integer","format":"int32"},"sells":{"type":"integer","format":"int32"},"unique_traders":{"type":"integer","format":"int32"},"price_open":{"type":"number","format":"double"},"price_high":{"type":"number","format":"double"},"price_low":{"type":"number","format":"double"},"price_close":{"type":"number","format":"double"}}},"PositionPnlSortBy":{"type":"string","enum":["realized_pnl_usd","buy_usd","sell_usd","redemption_usd","total_buys","total_sells","total_shares_bought","total_shares_sold","avg_entry_price","avg_exit_price","total_fees","first_trade_at","last_trade_at","current_value","realized_pnl_pct","title"]},"PositionStatus":{"type":"string","description":"Position status filter for open/closed positions.","enum":["open","closed"]},"PositionVolumeChartResponse":{"type":"object","required":["volumes","has_more"],"properties":{"volumes":{"type":"array","items":{"$ref":"#/components/schemas/PositionVolumeDataPoint"}},"has_more":{"type":"boolean"}}},"PositionVolumeDataPoint":{"type":"object","required":["t","v","bv","sv","tc","btc","stc"],"properties":{"t":{"type":"integer","format":"int64"},"v":{"type":"number","format":"double"},"bv":{"type":"number","format":"double"},"sv":{"type":"number","format":"double"},"tc":{"type":"integer","format":"int32"},"btc":{"type":"integer","format":"int32"},"stc":{"type":"integer","format":"int32"}}},"PositionsConvertedTrade":{"type":"object","description":"Output payload for NegRisk PositionsConverted trades\n(convert NO-position tokens → YES tokens + collateral).","required":["id","hash","trader","market_id","index_set","shares_amount","exchange"],"properties":{"id":{"type":"string"},"hash":{"type":"string"},"block":{"type":["integer","null"],"format":"int64","minimum":0},"confirmed_at":{"type":["integer","null"],"format":"int64","minimum":0},"received_at":{"type":["integer","null"],"format":"int64","minimum":0},"log_index":{"type":["integer","null"],"format":"int64","minimum":0},"block_index":{"type":["integer","null"],"format":"int64","minimum":0},"trader":{"$ref":"#/components/schemas/TraderInfo"},"market_id":{"type":"string","description":"NegRisk umbrella market ID"},"index_set":{"type":"string","description":"Bitmask of question indices whose NO tokens are being converted"},"shares_amount":{"type":"number","format":"double"},"exchange":{"$ref":"#/components/schemas/PolymarketExchange"}}},"PredictionCandlestickBar":{"type":"object","required":["t"],"properties":{"l":{"type":["number","null"],"format":"double"},"h":{"type":["number","null"],"format":"double"},"o":{"type":["number","null"],"format":"double"},"c":{"type":["number","null"],"format":"double"},"v":{"type":["number","null"],"format":"double"},"t":{"type":"integer","format":"int64","minimum":0},"tc":{"type":["integer","null"],"format":"int32"},"m":{"type":["number","null"],"format":"double"}}},"PriceJump":{"type":"object","required":["from","to","price_before","price_after","change_pct","direction","volume","trades_count","condition_id"],"properties":{"from":{"type":"integer","format":"int64","minimum":0},"to":{"type":"integer","format":"int64","minimum":0},"price_before":{"type":"number","format":"double"},"price_after":{"type":"number","format":"double"},"change_pct":{"type":"number","format":"double"},"direction":{"type":"string"},"volume":{"type":"number","format":"double"},"trades_count":{"type":"integer","format":"int32"},"condition_id":{"type":"string"}}},"QuestionEmergencyResolvedEvent":{"type":"object","description":"UMA CTF Adapter: admin emergency resolution.","required":["id","hash","oracle_contract","condition_id"],"properties":{"id":{"type":"string"},"hash":{"type":"string"},"block":{"type":["integer","null"],"format":"int64","minimum":0},"confirmed_at":{"type":["integer","null"],"format":"int64","minimum":0},"received_at":{"type":["integer","null"],"format":"int64","minimum":0},"log_index":{"type":["integer","null"],"format":"int64","minimum":0},"block_index":{"type":["integer","null"],"format":"int64","minimum":0},"oracle_contract":{"type":"string"},"condition_id":{"type":"string"},"proposed_outcome":{"type":["string","null"]},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"slug":{"type":["string","null"]},"event_slug":{"type":["string","null"]}}},"QuestionFlaggedEvent":{"type":"object","description":"UMA CTF Adapter: market flagged for emergency resolution.","required":["id","hash","oracle_contract","condition_id"],"properties":{"id":{"type":"string"},"hash":{"type":"string"},"block":{"type":["integer","null"],"format":"int64","minimum":0},"confirmed_at":{"type":["integer","null"],"format":"int64","minimum":0},"received_at":{"type":["integer","null"],"format":"int64","minimum":0},"log_index":{"type":["integer","null"],"format":"int64","minimum":0},"block_index":{"type":["integer","null"],"format":"int64","minimum":0},"oracle_contract":{"type":"string"},"condition_id":{"type":"string"},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"slug":{"type":["string","null"]},"event_slug":{"type":["string","null"]}}},"QuestionInitializedEvent":{"type":"object","description":"UMA CTF Adapter: questionID first initialized on-chain.","required":["id","hash","oracle_contract","condition_id","creator","reward_token","reward","proposal_bond"],"properties":{"id":{"type":"string"},"hash":{"type":"string"},"block":{"type":["integer","null"],"format":"int64","minimum":0},"confirmed_at":{"type":["integer","null"],"format":"int64","minimum":0},"received_at":{"type":["integer","null"],"format":"int64","minimum":0},"log_index":{"type":["integer","null"],"format":"int64","minimum":0},"block_index":{"type":["integer","null"],"format":"int64","minimum":0},"oracle_contract":{"type":"string"},"condition_id":{"type":"string"},"creator":{"type":"string"},"reward_token":{"type":"string"},"reward":{"type":"string"},"proposal_bond":{"type":"string"},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"slug":{"type":["string","null"]},"event_slug":{"type":["string","null"]}}},"QuestionPausedEvent":{"type":"object","description":"UMA CTF Adapter: market paused by admin.","required":["id","hash","oracle_contract","condition_id"],"properties":{"id":{"type":"string"},"hash":{"type":"string"},"block":{"type":["integer","null"],"format":"int64","minimum":0},"confirmed_at":{"type":["integer","null"],"format":"int64","minimum":0},"received_at":{"type":["integer","null"],"format":"int64","minimum":0},"log_index":{"type":["integer","null"],"format":"int64","minimum":0},"block_index":{"type":["integer","null"],"format":"int64","minimum":0},"oracle_contract":{"type":"string"},"condition_id":{"type":"string"},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"slug":{"type":["string","null"]},"event_slug":{"type":["string","null"]}}},"QuestionResetEvent":{"type":"object","description":"UMA CTF Adapter: dispute succeeded, market returns to active.","required":["id","hash","oracle_contract","condition_id"],"properties":{"id":{"type":"string"},"hash":{"type":"string"},"block":{"type":["integer","null"],"format":"int64","minimum":0},"confirmed_at":{"type":["integer","null"],"format":"int64","minimum":0},"received_at":{"type":["integer","null"],"format":"int64","minimum":0},"log_index":{"type":["integer","null"],"format":"int64","minimum":0},"block_index":{"type":["integer","null"],"format":"int64","minimum":0},"oracle_contract":{"type":"string"},"condition_id":{"type":"string"},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"slug":{"type":["string","null"]},"event_slug":{"type":["string","null"]}}},"QuestionResolvedEvent":{"type":"object","description":"UMA CTF Adapter: market resolved with definitive outcome.","required":["id","hash","oracle_contract","condition_id","settled_price"],"properties":{"id":{"type":"string"},"hash":{"type":"string"},"block":{"type":["integer","null"],"format":"int64","minimum":0},"confirmed_at":{"type":["integer","null"],"format":"int64","minimum":0},"received_at":{"type":["integer","null"],"format":"int64","minimum":0},"log_index":{"type":["integer","null"],"format":"int64","minimum":0},"block_index":{"type":["integer","null"],"format":"int64","minimum":0},"oracle_contract":{"type":"string"},"condition_id":{"type":"string"},"settled_price":{"type":"integer","format":"int64"},"proposed_outcome":{"type":["string","null"]},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"slug":{"type":["string","null"]},"event_slug":{"type":["string","null"]}}},"QuestionUnflaggedEvent":{"type":"object","description":"UMA CTF Adapter: flag removed.","required":["id","hash","oracle_contract","condition_id"],"properties":{"id":{"type":"string"},"hash":{"type":"string"},"block":{"type":["integer","null"],"format":"int64","minimum":0},"confirmed_at":{"type":["integer","null"],"format":"int64","minimum":0},"received_at":{"type":["integer","null"],"format":"int64","minimum":0},"log_index":{"type":["integer","null"],"format":"int64","minimum":0},"block_index":{"type":["integer","null"],"format":"int64","minimum":0},"oracle_contract":{"type":"string"},"condition_id":{"type":"string"},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"slug":{"type":["string","null"]},"event_slug":{"type":["string","null"]}}},"QuestionUnpausedEvent":{"type":"object","description":"UMA CTF Adapter: market unpaused.","required":["id","hash","oracle_contract","condition_id"],"properties":{"id":{"type":"string"},"hash":{"type":"string"},"block":{"type":["integer","null"],"format":"int64","minimum":0},"confirmed_at":{"type":["integer","null"],"format":"int64","minimum":0},"received_at":{"type":["integer","null"],"format":"int64","minimum":0},"log_index":{"type":["integer","null"],"format":"int64","minimum":0},"block_index":{"type":["integer","null"],"format":"int64","minimum":0},"oracle_contract":{"type":"string"},"condition_id":{"type":"string"},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"slug":{"type":["string","null"]},"event_slug":{"type":["string","null"]}}},"RedemptionTrade":{"type":"object","description":"Output payload for Redemption trades (payout after market resolution).","required":["id","hash","trader","usd_amount","exchange"],"properties":{"id":{"type":"string"},"hash":{"type":"string"},"block":{"type":["integer","null"],"format":"int64","minimum":0},"confirmed_at":{"type":["integer","null"],"format":"int64","minimum":0},"received_at":{"type":["integer","null"],"format":"int64","minimum":0},"log_index":{"type":["integer","null"],"format":"int64","minimum":0},"block_index":{"type":["integer","null"],"format":"int64","minimum":0},"trader":{"$ref":"#/components/schemas/TraderInfo"},"condition_id":{"type":["string","null"]},"outcome":{"type":["string","null"]},"outcome_index":{"type":["integer","null"],"format":"int32","minimum":0},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"slug":{"type":["string","null"]},"event_slug":{"type":["string","null"]},"usd_amount":{"type":"number","format":"double"},"winning_outcome_index":{"type":["integer","null"],"format":"int32","minimum":0},"position_details":{"type":"array","items":{"$ref":"#/components/schemas/PositionDetail"},"description":"Per-position burn amounts"},"exchange":{"$ref":"#/components/schemas/PolymarketExchange"}}},"RegisterTokenTrade":{"type":"object","description":"Output payload for RegisterToken events (YES/NO token pair registered for a condition).","required":["id","hash","condition_id","token0","token1","exchange"],"properties":{"id":{"type":"string"},"hash":{"type":"string"},"block":{"type":["integer","null"],"format":"int64","minimum":0},"confirmed_at":{"type":["integer","null"],"format":"int64","minimum":0},"received_at":{"type":["integer","null"],"format":"int64","minimum":0},"log_index":{"type":["integer","null"],"format":"int64","minimum":0},"block_index":{"type":["integer","null"],"format":"int64","minimum":0},"condition_id":{"type":"string"},"token0":{"type":"string"},"token1":{"type":"string"},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"slug":{"type":["string","null"]},"event_slug":{"type":["string","null"]},"exchange":{"$ref":"#/components/schemas/PolymarketExchange"}}},"SearchResponse":{"type":"object","properties":{"events":{"type":["array","null"],"items":{"$ref":"#/components/schemas/PolymarketEvent"}},"events_pagination":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PaginationMeta"}]},"markets":{"type":["array","null"],"items":{"$ref":"#/components/schemas/MarketResponse"}},"markets_pagination":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PaginationMeta"}]},"traders":{"type":["array","null"],"items":{"$ref":"#/components/schemas/TraderWithPnl"}},"traders_pagination":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/PaginationMeta"}]}}},"SearchSortBy":{"type":"string","description":"Combined sort options valid for both events and markets in search","enum":["volume","txns","unique_traders","relevance","title","creation_date","start_date","end_date","liquidity","holders","end_time","start_time","created_time"]},"SimpleTimeframeMetrics":{"type":"object","properties":{"volume":{"type":"number","format":"double","default":0.0},"fees":{"type":"number","format":"double","default":0.0},"txns":{"type":"integer","format":"int32","default":0},"unique_traders":{"type":"integer","format":"int32","default":0}}},"SortDirection":{"type":"string","enum":["asc","desc"]},"SpikeDirection":{"type":"string","description":"Direction filter for spike webhooks.","enum":["up","down","both"]},"SplitTrade":{"type":"object","description":"Output payload for Split trades (deposit collateral → receive outcome tokens).","required":["id","hash","trader","usd_amount","exchange"],"properties":{"id":{"type":"string"},"hash":{"type":"string"},"block":{"type":["integer","null"],"format":"int64","minimum":0},"confirmed_at":{"type":["integer","null"],"format":"int64","minimum":0},"received_at":{"type":["integer","null"],"format":"int64","minimum":0},"log_index":{"type":["integer","null"],"format":"int64","minimum":0},"block_index":{"type":["integer","null"],"format":"int64","minimum":0},"trader":{"$ref":"#/components/schemas/TraderInfo"},"condition_id":{"type":["string","null"]},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"slug":{"type":["string","null"]},"event_slug":{"type":["string","null"]},"usd_amount":{"type":"number","format":"double"},"position_details":{"type":"array","items":{"$ref":"#/components/schemas/PositionDetail"},"description":"Per-position mint amounts"},"exchange":{"$ref":"#/components/schemas/PolymarketExchange"}}},"SpreadRow":{"type":"object","description":"Lightweight row — derived metrics only, no bids/asks JSONB.","required":["ts","position_id","condition_id"],"properties":{"ts":{"type":"integer","format":"int64"},"position_id":{"type":"string"},"condition_id":{"type":"string"},"best_bid":{"type":["number","null"],"format":"double"},"best_ask":{"type":["number","null"],"format":"double"},"mid_price":{"type":["number","null"],"format":"double"},"spread":{"type":["number","null"],"format":"double"},"bid_liquidity_usd":{"type":["number","null"],"format":"double"},"ask_liquidity_usd":{"type":["number","null"],"format":"double"},"bid_levels":{"type":["integer","null"],"format":"int32"},"ask_levels":{"type":["integer","null"],"format":"int32"}}},"TokenOutcome":{"type":"object","description":"Token outcome (position)","required":["token_id","outcome"],"properties":{"token_id":{"type":"string"},"outcome":{"type":"string"}}},"TradeEvent":{"oneOf":[{"allOf":[{"$ref":"#/components/schemas/OrderFilledTrade"},{"type":"object","required":["trade_type"],"properties":{"trade_type":{"type":"string","enum":["OrderFilled"]}}}]},{"allOf":[{"$ref":"#/components/schemas/OrderFilledTrade"},{"type":"object","required":["trade_type"],"properties":{"trade_type":{"type":"string","enum":["OrdersMatched"]}}}]},{"allOf":[{"$ref":"#/components/schemas/RedemptionTrade"},{"type":"object","required":["trade_type"],"properties":{"trade_type":{"type":"string","enum":["Redemption"]}}}]},{"allOf":[{"$ref":"#/components/schemas/MergeTrade"},{"type":"object","required":["trade_type"],"properties":{"trade_type":{"type":"string","enum":["Merge"]}}}]},{"allOf":[{"$ref":"#/components/schemas/SplitTrade"},{"type":"object","required":["trade_type"],"properties":{"trade_type":{"type":"string","enum":["Split"]}}}]},{"allOf":[{"$ref":"#/components/schemas/PositionsConvertedTrade"},{"type":"object","required":["trade_type"],"properties":{"trade_type":{"type":"string","enum":["PositionsConverted"]}}}]},{"allOf":[{"$ref":"#/components/schemas/CancelledTrade"},{"type":"object","required":["trade_type"],"properties":{"trade_type":{"type":"string","enum":["Cancelled"]}}}]},{"allOf":[{"$ref":"#/components/schemas/QuestionInitializedEvent"},{"type":"object","required":["trade_type"],"properties":{"trade_type":{"type":"string","enum":["Initialization"]}}}]},{"allOf":[{"$ref":"#/components/schemas/AssertionMadeEvent"},{"type":"object","required":["trade_type"],"properties":{"trade_type":{"type":"string","enum":["Proposal"]}}}]},{"allOf":[{"$ref":"#/components/schemas/AssertionDisputedEvent"},{"type":"object","required":["trade_type"],"properties":{"trade_type":{"type":"string","enum":["Dispute"]}}}]},{"allOf":[{"$ref":"#/components/schemas/AssertionSettledEvent"},{"type":"object","required":["trade_type"],"properties":{"trade_type":{"type":"string","enum":["Settled"]}}}]},{"allOf":[{"$ref":"#/components/schemas/QuestionResolvedEvent"},{"type":"object","required":["trade_type"],"properties":{"trade_type":{"type":"string","enum":["Resolution"]}}}]},{"allOf":[{"$ref":"#/components/schemas/ConditionResolutionEvent"},{"type":"object","required":["trade_type"],"properties":{"trade_type":{"type":"string","enum":["ConditionResolution"]}}}]},{"allOf":[{"$ref":"#/components/schemas/QuestionResetEvent"},{"type":"object","required":["trade_type"],"properties":{"trade_type":{"type":"string","enum":["Reset"]}}}]},{"allOf":[{"$ref":"#/components/schemas/QuestionFlaggedEvent"},{"type":"object","required":["trade_type"],"properties":{"trade_type":{"type":"string","enum":["Flag"]}}}]},{"allOf":[{"$ref":"#/components/schemas/QuestionUnflaggedEvent"},{"type":"object","required":["trade_type"],"properties":{"trade_type":{"type":"string","enum":["Unflag"]}}}]},{"allOf":[{"$ref":"#/components/schemas/QuestionPausedEvent"},{"type":"object","required":["trade_type"],"properties":{"trade_type":{"type":"string","enum":["Pause"]}}}]},{"allOf":[{"$ref":"#/components/schemas/QuestionUnpausedEvent"},{"type":"object","required":["trade_type"],"properties":{"trade_type":{"type":"string","enum":["Unpause"]}}}]},{"allOf":[{"$ref":"#/components/schemas/QuestionEmergencyResolvedEvent"},{"type":"object","required":["trade_type"],"properties":{"trade_type":{"type":"string","enum":["ManualResolution"]}}}]},{"allOf":[{"$ref":"#/components/schemas/NegRiskOutcomeReportedEvent"},{"type":"object","required":["trade_type"],"properties":{"trade_type":{"type":"string","enum":["NegRiskOutcomeReported"]}}}]},{"allOf":[{"$ref":"#/components/schemas/RegisterTokenTrade"},{"type":"object","required":["trade_type"],"properties":{"trade_type":{"type":"string","enum":["RegisterToken"]}}}]},{"allOf":[{"$ref":"#/components/schemas/ApprovalTrade"},{"type":"object","required":["trade_type"],"properties":{"trade_type":{"type":"string","enum":["Approval"]}}}]}],"description":"Tagged enum for all trade types — serializes with `\"trade_type\": \"...\"` discriminator\nand only includes fields relevant to each type."},"TradeSide":{"type":"string","enum":["0","1"]},"TradeType":{"type":"string","enum":["0","1","2","3","4","5","6"]},"Trader":{"type":"object","description":"Trader profile info embedded in API responses\n\nCorresponds to SQL function: `pm_build_trader(address, name, pseudonym, profile_image, x_username, verified_badge)`\n\nUsed in:\n- holders endpoints (market/event holders)\n- trades endpoints\n- leaderboard endpoints","required":["address"],"properties":{"address":{"type":"string"},"name":{"type":["string","null"]},"pseudonym":{"type":["string","null"]},"profile_image":{"type":["string","null"]},"x_username":{"type":["string","null"]},"verified_badge":{"type":"boolean"}}},"TraderEventPnlEntry":{"type":"object","description":"Event-level PnL entry","properties":{"event_slug":{"type":["string","null"]},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"markets_traded":{"type":["integer","null"],"format":"int64"},"outcomes_traded":{"type":["integer","null"],"format":"int64"},"total_buys":{"type":["integer","null"],"format":"int64"},"total_sells":{"type":["integer","null"],"format":"int64"},"total_redemptions":{"type":["integer","null"],"format":"int64"},"total_merges":{"type":["integer","null"],"format":"int64"},"total_volume_usd":{"type":["number","null"],"format":"double"},"buy_usd":{"type":["number","null"],"format":"double"},"sell_usd":{"type":["number","null"],"format":"double"},"redemption_usd":{"type":["number","null"],"format":"double"},"merge_usd":{"type":["number","null"],"format":"double"},"realized_pnl_usd":{"type":["number","null"],"format":"double"},"winning_markets":{"type":["integer","null"],"format":"int64"},"losing_markets":{"type":["integer","null"],"format":"int64"},"total_fees":{"type":["number","null"],"format":"double"},"first_trade_at":{"type":["integer","null"],"format":"int64"},"last_trade_at":{"type":["integer","null"],"format":"int64"}}},"TraderInfo":{"type":"object","description":"Trader profile info - backwards compatibility","required":["address"],"properties":{"address":{"type":"string"},"name":{"type":["string","null"]},"pseudonym":{"type":["string","null"]},"profile_image":{"type":["string","null"]},"x_username":{"type":["string","null"]},"verified_badge":{"type":"boolean"}}},"TraderMarketPnlEntry":{"type":"object","description":"Market-level PnL entry","properties":{"condition_id":{"type":["string","null"]},"event_slug":{"type":["string","null"]},"question":{"type":["string","null"]},"image_url":{"type":["string","null"]},"outcomes_traded":{"type":["integer","null"],"format":"int64"},"total_buys":{"type":["integer","null"],"format":"int64"},"total_sells":{"type":["integer","null"],"format":"int64"},"total_redemptions":{"type":["integer","null"],"format":"int64"},"total_merges":{"type":["integer","null"],"format":"int64"},"buy_usd":{"type":["number","null"],"format":"double"},"sell_usd":{"type":["number","null"],"format":"double"},"redemption_usd":{"type":["number","null"],"format":"double"},"merge_usd":{"type":["number","null"],"format":"double"},"realized_pnl_usd":{"type":["number","null"],"format":"double"},"winning_outcomes":{"type":["integer","null"],"format":"int64"},"total_fees":{"type":["number","null"],"format":"double"},"first_trade_at":{"type":["integer","null"],"format":"int64"},"last_trade_at":{"type":["integer","null"],"format":"int64"}}},"TraderOutcomePnlEntry":{"type":"object","description":"Outcome-level PnL entry (per outcome token / position_id)","properties":{"position_id":{"type":["string","null"]},"condition_id":{"type":["string","null"]},"market_slug":{"type":["string","null"]},"event_slug":{"type":["string","null"]},"title":{"type":["string","null"]},"image_url":{"type":["string","null"]},"outcome":{"type":["string","null"]},"outcome_index":{"type":["integer","null"],"format":"int32"},"won":{"type":["boolean","null"],"description":"TRUE = won, FALSE = lost, NULL = open or sold before resolution"},"total_buys":{"type":["integer","null"],"format":"int64"},"total_sells":{"type":["integer","null"],"format":"int64"},"total_shares_bought":{"type":["number","null"],"format":"double"},"total_shares_sold":{"type":["number","null"],"format":"double"},"total_buy_usd":{"type":["number","null"],"format":"double"},"total_sell_usd":{"type":["number","null"],"format":"double"},"redemption_usd":{"type":["number","null"],"format":"double","description":"Payout on redemption (non-zero only if won)"},"avg_entry_price":{"type":["number","null"],"format":"double","description":"VWAP price paid per share across all buys (0–1)"},"avg_exit_price":{"type":["number","null"],"format":"double","description":"VWAP price received per share across all sells (0–1)"},"realized_pnl_usd":{"type":["number","null"],"format":"double"},"total_fees":{"type":["number","null"],"format":"double"},"first_trade_at":{"type":["integer","null"],"format":"int64"},"last_trade_at":{"type":["integer","null"],"format":"int64"},"current_price":{"type":["number","null"],"format":"double","description":"Last traded price for this outcome (0–1). NULL if market_outcomes has no price yet."},"current_shares_balance":{"type":["number","null"],"format":"double","description":"Current shares held: balance / 1e6."},"current_value":{"type":["number","null"],"format":"double","description":"Estimated current USD value of held shares: (balance / 1e6) * current_price.\nOnly meaningful for open positions (balance above dust threshold)."},"realized_pnl_pct":{"type":["number","null"],"format":"double","description":"Realized PnL as a percentage of total spend: (realized_pnl_usd / total_buy_usd) * 100.\nNULL when total_buy_usd = 0."}}},"TraderPnlSummary":{"type":"object","description":"Trader's global PnL summary (single trader)","properties":{"trader":{"type":["string","null"]},"realized_pnl_usd":{"type":["number","null"],"format":"double"},"events_traded":{"type":["integer","null"],"format":"int64"},"markets_traded":{"type":["integer","null"],"format":"int64"},"total_buys":{"type":["integer","null"],"format":"int64"},"total_sells":{"type":["integer","null"],"format":"int64"},"total_redemptions":{"type":["integer","null"],"format":"int64"},"total_merges":{"type":["integer","null"],"format":"int64"},"total_volume_usd":{"type":["number","null"],"format":"double"},"buy_volume_usd":{"type":["number","null"],"format":"double"},"sell_volume_usd":{"type":["number","null"],"format":"double"},"redemption_volume_usd":{"type":["number","null"],"format":"double"},"merge_volume_usd":{"type":["number","null"],"format":"double"},"markets_won":{"type":["integer","null"],"format":"int64"},"markets_lost":{"type":["integer","null"],"format":"int64"},"market_win_rate_pct":{"type":["number","null"],"format":"double"},"avg_pnl_per_market":{"type":["number","null"],"format":"double"},"avg_pnl_per_trade":{"type":["number","null"],"format":"double"},"avg_hold_time_seconds":{"type":["number","null"],"format":"double"},"total_fees":{"type":["number","null"],"format":"double"},"best_trade_pnl_usd":{"type":["number","null"],"format":"double"},"best_trade_condition_id":{"type":["string","null"]},"first_trade_at":{"type":["integer","null"],"format":"int64"},"last_trade_at":{"type":["integer","null"],"format":"int64"}}},"TraderVolumeChartResponse":{"type":"object","required":["volumes","has_more"],"properties":{"volumes":{"type":"array","items":{"$ref":"#/components/schemas/TraderVolumeDataPoint"}},"has_more":{"type":"boolean"}}},"TraderVolumeDataPoint":{"type":"object","required":["t","v","bv","sv","tc","btc","stc"],"properties":{"t":{"type":"integer","format":"int64"},"v":{"type":"number","format":"double"},"bv":{"type":"number","format":"double"},"sv":{"type":"number","format":"double"},"tc":{"type":"integer","format":"int32"},"btc":{"type":"integer","format":"int32"},"stc":{"type":"integer","format":"int32"}}},"TraderWithPnl":{"allOf":[{"$ref":"#/components/schemas/Trader"},{"type":"object","properties":{"pnl":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/TraderPnlSummary"}]}}}]},"WebhookAssetSymbol":{"type":"string","description":"Crypto asset symbols accepted by `asset_price_tick` and `asset_price_window_update` filters.","enum":["BTC","ETH","SOL","XRP","DOGE","BNB","HYPE"]},"WebhookTimeframe":{"type":"string","description":"Timeframe values accepted by webhook metric, milestone, spike, and asset-price filters.","enum":["1m","5m","15m","30m","1h","4h","6h","1d","24h","7d","30d"]}}}} \ No newline at end of file diff --git a/openapi/ws-alerts.json b/openapi/ws-alerts.json new file mode 100644 index 0000000..ef6ffeb --- /dev/null +++ b/openapi/ws-alerts.json @@ -0,0 +1,9663 @@ +{ + "asyncapi": "3.0.0", + "info": { + "title": "Polymarket WebSocket Alerts API", + "version": "1.0.0", + "description": "Real-time alert subscriptions delivered over WebSocket. Same events and filters as HTTP webhooks — ephemeral delivery that ends when the connection closes. The alerts WS path shares the same event/filter pipeline as HTTP webhooks; only delivery transport differs.\n\n## Connection\n\n```\nwss://api.struct.to/ws/alerts\n```\n\nAll alert channels share the same physical endpoint — each channel in this spec represents one event type you can subscribe to.\n\n## Authentication\n\nTwo authentication methods are supported:\n\n**1. API key** (`apiKeyHeader` or `apiKeyQuery`):\n```\nX-Api-Key: \n```\nor\n```\nwss://api.struct.to/ws/alerts?api-key=\n```\n\n**2. Public-key JWT combo** (`publicKeyJwt`): for builders who embed a `pk_jwt_*` key in their frontend and issue JWTs to their end users. Credits bill to the builder's org; rate limits are per session.\n```\nAuthorization: Bearer \n```\nor\n```\nwss://api.struct.to/ws/alerts?token=\n```\n\n## Protocol\n\nAfter connecting, send JSON messages to subscribe or unsubscribe:\n\n```json\n{ \"op\": \"subscribe\", \"event\": \"trader_whale_trade\", \"min_usd_value\": 10000 }\n```\n\nServer responds with `{\"op\":\"subscribed\", ...}`. Pushed alert events use the format `{\"event\":\"...\",\"timestamp\":...,\"data\": ...}`.\n\n## Keepalive\n\nSend `{\"type\":\"ping\"}` periodically to keep your connection alive. The server responds with `{\"type\":\"pong\"}`. Connections that have not received **any** frame (ping, subscribe, or unsubscribe) within **60 seconds** are closed. Recommended: send a ping every 30 seconds.\n\n## Pricing\n\nEach delivered alert costs **1-2 credits**, matching the corresponding HTTP webhook cost exactly. See each channel's description for its specific credit cost." + }, + "servers": { + "alerts": { + "host": "api.struct.to", + "pathname": "/ws/alerts", + "protocol": "wss", + "description": "WebSocket alerts endpoint — ephemeral real-time alert subscriptions. Pass API key via ?api-key= query parameter. Subscribe/unsubscribe by sending JSON messages. Subscriptions are ephemeral and end on disconnect." + } + }, + "channels": { + "ws_alerts.trader_first_trade": { + "address": "/ws/alerts", + "title": "First Trade", + "summary": "Real-time `trader_first_trade` alert subscription", + "description": "Fired when a tracked trader executes their first trade on Polymarket\n\n**Credits cost:** 1 per delivered alert.\n\n**Applicable filters:** `wallet_addresses`, `min_usd_value`, `min_probability`, `max_probability`, `condition_ids`, `event_slugs`, `exclude_shortterm_markets`\n\nConnection: `wss://api.struct.to/ws/alerts?api-key=` — all alert channels share the same physical endpoint.", + "servers": [ + { + "$ref": "#/servers/alerts" + } + ], + "tags": [ + { + "name": "trader" + } + ], + "messages": { + "subscribe": { + "$ref": "#/components/messages/WsAlertTraderFirstTradeSubscribe" + }, + "unsubscribe": { + "$ref": "#/components/messages/WsAlertTraderFirstTradeUnsubscribe" + }, + "event": { + "$ref": "#/components/messages/WsAlertTraderFirstTradeEvent" + }, + "subscribed": { + "$ref": "#/components/messages/WsAlertSubscribed" + }, + "unsubscribed": { + "$ref": "#/components/messages/WsAlertUnsubscribed" + }, + "error": { + "$ref": "#/components/messages/WsAlertError" + } + } + }, + "ws_alerts.trader_new_market": { + "address": "/ws/alerts", + "title": "New Market Entry", + "summary": "Real-time `trader_new_market` alert subscription", + "description": "Fired when a trader places their first trade in a specific market/condition (fires once per trader+market pair)\n\n**Credits cost:** 1 per delivered alert.\n\n**Applicable filters:** `wallet_addresses`, `condition_ids`, `event_slugs`, `min_usd_value`, `min_probability`, `max_probability`, `exclude_shortterm_markets`\n\nConnection: `wss://api.struct.to/ws/alerts?api-key=` — all alert channels share the same physical endpoint.", + "servers": [ + { + "$ref": "#/servers/alerts" + } + ], + "tags": [ + { + "name": "trader" + } + ], + "messages": { + "subscribe": { + "$ref": "#/components/messages/WsAlertTraderNewMarketSubscribe" + }, + "unsubscribe": { + "$ref": "#/components/messages/WsAlertTraderNewMarketUnsubscribe" + }, + "event": { + "$ref": "#/components/messages/WsAlertTraderNewMarketEvent" + }, + "subscribed": { + "$ref": "#/components/messages/WsAlertSubscribed" + }, + "unsubscribed": { + "$ref": "#/components/messages/WsAlertUnsubscribed" + }, + "error": { + "$ref": "#/components/messages/WsAlertError" + } + } + }, + "ws_alerts.trader_whale_trade": { + "address": "/ws/alerts", + "title": "Whale Trade", + "summary": "Real-time `trader_whale_trade` alert subscription", + "description": "Fired when a trade meets the configured criteria. Use `min_usd_value` to filter by minimum trade size (optional, defaults to 0 — matches all trades), and `min_probability`/`max_probability` to restrict to a probability range.\n\n**Credits cost:** 2 per delivered alert.\n\n**Applicable filters:** `wallet_addresses`, `min_usd_value`, `min_probability`, `max_probability`, `condition_ids`, `event_slugs`, `exclude_shortterm_markets`\n\nConnection: `wss://api.struct.to/ws/alerts?api-key=` — all alert channels share the same physical endpoint.", + "servers": [ + { + "$ref": "#/servers/alerts" + } + ], + "tags": [ + { + "name": "trader" + } + ], + "messages": { + "subscribe": { + "$ref": "#/components/messages/WsAlertTraderWhaleTradeSubscribe" + }, + "unsubscribe": { + "$ref": "#/components/messages/WsAlertTraderWhaleTradeUnsubscribe" + }, + "event": { + "$ref": "#/components/messages/WsAlertTraderWhaleTradeEvent" + }, + "subscribed": { + "$ref": "#/components/messages/WsAlertSubscribed" + }, + "unsubscribed": { + "$ref": "#/components/messages/WsAlertUnsubscribed" + }, + "error": { + "$ref": "#/components/messages/WsAlertError" + } + } + }, + "ws_alerts.trader_new_trade": { + "address": "/ws/alerts", + "title": "New Trade", + "summary": "Real-time `trader_new_trade` alert subscription", + "description": "Fired on every order-filled trade. Use `wallet_addresses` to watch specific traders, `min_usd_value` to filter by size, and `min_probability`/`max_probability` to restrict to a probability range.\n\n**Credits cost:** 2 per delivered alert.\n\n**Applicable filters:** `wallet_addresses`, `min_usd_value`, `min_probability`, `max_probability`, `condition_ids`, `event_slugs`, `exclude_shortterm_markets`\n\nConnection: `wss://api.struct.to/ws/alerts?api-key=` — all alert channels share the same physical endpoint.", + "servers": [ + { + "$ref": "#/servers/alerts" + } + ], + "tags": [ + { + "name": "trader" + } + ], + "messages": { + "subscribe": { + "$ref": "#/components/messages/WsAlertTraderNewTradeSubscribe" + }, + "unsubscribe": { + "$ref": "#/components/messages/WsAlertTraderNewTradeUnsubscribe" + }, + "event": { + "$ref": "#/components/messages/WsAlertTraderNewTradeEvent" + }, + "subscribed": { + "$ref": "#/components/messages/WsAlertSubscribed" + }, + "unsubscribed": { + "$ref": "#/components/messages/WsAlertUnsubscribed" + }, + "error": { + "$ref": "#/components/messages/WsAlertError" + } + } + }, + "ws_alerts.trader_global_pnl": { + "address": "/ws/alerts", + "title": "Global PnL", + "summary": "Real-time `trader_global_pnl` alert subscription", + "description": "Fired when a trader's global PnL crosses a configured threshold\n\n**Credits cost:** 1 per delivered alert.\n\n**Applicable filters:** `traders`, `min_realized_pnl_usd`, `max_realized_pnl_usd`, `min_volume_usd`, `max_volume_usd`, `min_buy_usd`, `min_sell_volume_usd`, `min_win_rate`, `min_markets_traded`, `timeframes`\n\nConnection: `wss://api.struct.to/ws/alerts?api-key=` — all alert channels share the same physical endpoint.", + "servers": [ + { + "$ref": "#/servers/alerts" + } + ], + "tags": [ + { + "name": "trader" + } + ], + "messages": { + "subscribe": { + "$ref": "#/components/messages/WsAlertTraderGlobalPnlSubscribe" + }, + "unsubscribe": { + "$ref": "#/components/messages/WsAlertTraderGlobalPnlUnsubscribe" + }, + "event": { + "$ref": "#/components/messages/WsAlertTraderGlobalPnlEvent" + }, + "subscribed": { + "$ref": "#/components/messages/WsAlertSubscribed" + }, + "unsubscribed": { + "$ref": "#/components/messages/WsAlertUnsubscribed" + }, + "error": { + "$ref": "#/components/messages/WsAlertError" + } + } + }, + "ws_alerts.trader_market_pnl": { + "address": "/ws/alerts", + "title": "Market PnL", + "summary": "Real-time `trader_market_pnl` alert subscription", + "description": "Fired when a trader's market-level PnL crosses a configured threshold\n\n**Credits cost:** 1 per delivered alert.\n\n**Applicable filters:** `traders`, `condition_ids`, `event_slugs`, `min_realized_pnl_usd`, `max_realized_pnl_usd`, `min_volume_usd`, `max_volume_usd`, `min_buy_usd`, `min_sell_volume_usd`, `timeframes`, `exclude_shortterm_markets`\n\nConnection: `wss://api.struct.to/ws/alerts?api-key=` — all alert channels share the same physical endpoint.", + "servers": [ + { + "$ref": "#/servers/alerts" + } + ], + "tags": [ + { + "name": "trader" + } + ], + "messages": { + "subscribe": { + "$ref": "#/components/messages/WsAlertTraderMarketPnlSubscribe" + }, + "unsubscribe": { + "$ref": "#/components/messages/WsAlertTraderMarketPnlUnsubscribe" + }, + "event": { + "$ref": "#/components/messages/WsAlertTraderMarketPnlEvent" + }, + "subscribed": { + "$ref": "#/components/messages/WsAlertSubscribed" + }, + "unsubscribed": { + "$ref": "#/components/messages/WsAlertUnsubscribed" + }, + "error": { + "$ref": "#/components/messages/WsAlertError" + } + } + }, + "ws_alerts.trader_event_pnl": { + "address": "/ws/alerts", + "title": "Event PnL", + "summary": "Real-time `trader_event_pnl` alert subscription", + "description": "Fired when a trader's event-level PnL crosses a configured threshold\n\n**Credits cost:** 1 per delivered alert.\n\n**Applicable filters:** `traders`, `event_slugs`, `min_realized_pnl_usd`, `max_realized_pnl_usd`, `min_volume_usd`, `max_volume_usd`, `min_buy_usd`, `min_sell_volume_usd`, `min_markets_traded`, `timeframes`, `exclude_shortterm_markets`\n\nConnection: `wss://api.struct.to/ws/alerts?api-key=` — all alert channels share the same physical endpoint.", + "servers": [ + { + "$ref": "#/servers/alerts" + } + ], + "tags": [ + { + "name": "trader" + } + ], + "messages": { + "subscribe": { + "$ref": "#/components/messages/WsAlertTraderEventPnlSubscribe" + }, + "unsubscribe": { + "$ref": "#/components/messages/WsAlertTraderEventPnlUnsubscribe" + }, + "event": { + "$ref": "#/components/messages/WsAlertTraderEventPnlEvent" + }, + "subscribed": { + "$ref": "#/components/messages/WsAlertSubscribed" + }, + "unsubscribed": { + "$ref": "#/components/messages/WsAlertUnsubscribed" + }, + "error": { + "$ref": "#/components/messages/WsAlertError" + } + } + }, + "ws_alerts.condition_metrics": { + "address": "/ws/alerts", + "title": "Market Metrics", + "summary": "Real-time `condition_metrics` alert subscription", + "description": "Fired when a market's volume or transaction metrics cross a configured threshold. Use `timeframes` to restrict to specific windows (valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`).\n\n**Credits cost:** 1 per delivered alert.\n\n**Applicable filters:** `condition_ids`, `min_volume_usd`, `max_volume_usd`, `min_fees`, `min_txns`, `min_unique_traders`, `timeframes`\n\nConnection: `wss://api.struct.to/ws/alerts?api-key=` — all alert channels share the same physical endpoint.", + "servers": [ + { + "$ref": "#/servers/alerts" + } + ], + "tags": [ + { + "name": "market" + } + ], + "messages": { + "subscribe": { + "$ref": "#/components/messages/WsAlertConditionMetricsSubscribe" + }, + "unsubscribe": { + "$ref": "#/components/messages/WsAlertConditionMetricsUnsubscribe" + }, + "event": { + "$ref": "#/components/messages/WsAlertConditionMetricsEvent" + }, + "subscribed": { + "$ref": "#/components/messages/WsAlertSubscribed" + }, + "unsubscribed": { + "$ref": "#/components/messages/WsAlertUnsubscribed" + }, + "error": { + "$ref": "#/components/messages/WsAlertError" + } + } + }, + "ws_alerts.event_metrics": { + "address": "/ws/alerts", + "title": "Event Metrics", + "summary": "Real-time `event_metrics` alert subscription", + "description": "Fired when an event's volume or transaction metrics cross a configured threshold. Use `timeframes` to restrict to specific windows (valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`).\n\n**Credits cost:** 1 per delivered alert.\n\n**Applicable filters:** `event_slugs`, `min_volume_usd`, `max_volume_usd`, `min_fees`, `min_txns`, `min_unique_traders`, `timeframes`, `exclude_shortterm_markets`\n\nConnection: `wss://api.struct.to/ws/alerts?api-key=` — all alert channels share the same physical endpoint.", + "servers": [ + { + "$ref": "#/servers/alerts" + } + ], + "tags": [ + { + "name": "event" + } + ], + "messages": { + "subscribe": { + "$ref": "#/components/messages/WsAlertEventMetricsSubscribe" + }, + "unsubscribe": { + "$ref": "#/components/messages/WsAlertEventMetricsUnsubscribe" + }, + "event": { + "$ref": "#/components/messages/WsAlertEventMetricsEvent" + }, + "subscribed": { + "$ref": "#/components/messages/WsAlertSubscribed" + }, + "unsubscribed": { + "$ref": "#/components/messages/WsAlertUnsubscribed" + }, + "error": { + "$ref": "#/components/messages/WsAlertError" + } + } + }, + "ws_alerts.position_metrics": { + "address": "/ws/alerts", + "title": "Position Metrics", + "summary": "Real-time `position_metrics` alert subscription", + "description": "Fired when a position's volume or transaction metrics cross a configured threshold. Use `timeframes` to restrict to specific windows (valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`).\n\n**Credits cost:** 1 per delivered alert.\n\n**Applicable filters:** `position_ids`, `condition_ids`, `outcomes`, `min_volume_usd`, `max_volume_usd`, `min_buy_usd`, `min_sell_volume_usd`, `min_fees`, `min_txns`, `min_price_change_pct`, `min_probability_change_pct`, `timeframes`\n\nConnection: `wss://api.struct.to/ws/alerts?api-key=` — all alert channels share the same physical endpoint.", + "servers": [ + { + "$ref": "#/servers/alerts" + } + ], + "tags": [ + { + "name": "position" + } + ], + "messages": { + "subscribe": { + "$ref": "#/components/messages/WsAlertPositionMetricsSubscribe" + }, + "unsubscribe": { + "$ref": "#/components/messages/WsAlertPositionMetricsUnsubscribe" + }, + "event": { + "$ref": "#/components/messages/WsAlertPositionMetricsEvent" + }, + "subscribed": { + "$ref": "#/components/messages/WsAlertSubscribed" + }, + "unsubscribed": { + "$ref": "#/components/messages/WsAlertUnsubscribed" + }, + "error": { + "$ref": "#/components/messages/WsAlertError" + } + } + }, + "ws_alerts.market_volume_milestone": { + "address": "/ws/alerts", + "title": "Market Volume Milestone", + "summary": "Real-time `market_volume_milestone` alert subscription", + "description": "Fired when a market's trading volume crosses a milestone threshold in the specified timeframe. **`timeframes` is required** (e.g. `[\"1h\", \"24h\"]`) — valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`. Optional `milestone_amounts` restricts to specific USD thresholds (e.g. `[10000, 100000]`). Optional `condition_ids` restricts to specific markets.\n\n**Credits cost:** 2 per delivered alert.\n\n**Applicable filters:** `condition_ids`, `timeframes`, `milestone_amounts`\n\nConnection: `wss://api.struct.to/ws/alerts?api-key=` — all alert channels share the same physical endpoint.", + "servers": [ + { + "$ref": "#/servers/alerts" + } + ], + "tags": [ + { + "name": "market" + } + ], + "messages": { + "subscribe": { + "$ref": "#/components/messages/WsAlertMarketVolumeMilestoneSubscribe" + }, + "unsubscribe": { + "$ref": "#/components/messages/WsAlertMarketVolumeMilestoneUnsubscribe" + }, + "event": { + "$ref": "#/components/messages/WsAlertMarketVolumeMilestoneEvent" + }, + "subscribed": { + "$ref": "#/components/messages/WsAlertSubscribed" + }, + "unsubscribed": { + "$ref": "#/components/messages/WsAlertUnsubscribed" + }, + "error": { + "$ref": "#/components/messages/WsAlertError" + } + } + }, + "ws_alerts.event_volume_milestone": { + "address": "/ws/alerts", + "title": "Event Volume Milestone", + "summary": "Real-time `event_volume_milestone` alert subscription", + "description": "Fired when an event's trading volume crosses a milestone threshold in the specified timeframe. **`timeframes` is required** (e.g. `[\"1h\", \"24h\"]`) — valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`. Optional `milestone_amounts` restricts to specific USD thresholds. Optional `event_slugs` restricts to specific events.\n\n**Credits cost:** 2 per delivered alert.\n\n**Applicable filters:** `event_slugs`, `timeframes`, `milestone_amounts`, `exclude_shortterm_markets`\n\nConnection: `wss://api.struct.to/ws/alerts?api-key=` — all alert channels share the same physical endpoint.", + "servers": [ + { + "$ref": "#/servers/alerts" + } + ], + "tags": [ + { + "name": "event" + } + ], + "messages": { + "subscribe": { + "$ref": "#/components/messages/WsAlertEventVolumeMilestoneSubscribe" + }, + "unsubscribe": { + "$ref": "#/components/messages/WsAlertEventVolumeMilestoneUnsubscribe" + }, + "event": { + "$ref": "#/components/messages/WsAlertEventVolumeMilestoneEvent" + }, + "subscribed": { + "$ref": "#/components/messages/WsAlertSubscribed" + }, + "unsubscribed": { + "$ref": "#/components/messages/WsAlertUnsubscribed" + }, + "error": { + "$ref": "#/components/messages/WsAlertError" + } + } + }, + "ws_alerts.position_volume_milestone": { + "address": "/ws/alerts", + "title": "Position Volume Milestone", + "summary": "Real-time `position_volume_milestone` alert subscription", + "description": "Fired when a position's trading volume crosses a milestone threshold in the specified timeframe. **`timeframes` is required** (e.g. `[\"1h\", \"24h\"]`) — valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`. Optional `milestone_amounts` restricts to specific USD thresholds. Optional `position_ids` or `condition_ids` restrict to specific positions/markets.\n\n**Credits cost:** 2 per delivered alert.\n\n**Applicable filters:** `position_ids`, `condition_ids`, `outcomes`, `timeframes`, `milestone_amounts`\n\nConnection: `wss://api.struct.to/ws/alerts?api-key=` — all alert channels share the same physical endpoint.", + "servers": [ + { + "$ref": "#/servers/alerts" + } + ], + "tags": [ + { + "name": "position" + } + ], + "messages": { + "subscribe": { + "$ref": "#/components/messages/WsAlertPositionVolumeMilestoneSubscribe" + }, + "unsubscribe": { + "$ref": "#/components/messages/WsAlertPositionVolumeMilestoneUnsubscribe" + }, + "event": { + "$ref": "#/components/messages/WsAlertPositionVolumeMilestoneEvent" + }, + "subscribed": { + "$ref": "#/components/messages/WsAlertSubscribed" + }, + "unsubscribed": { + "$ref": "#/components/messages/WsAlertUnsubscribed" + }, + "error": { + "$ref": "#/components/messages/WsAlertError" + } + } + }, + "ws_alerts.probability_spike": { + "address": "/ws/alerts", + "title": "Probability Spike", + "summary": "Real-time `probability_spike` alert subscription", + "description": "Fired when a position's probability moves significantly. Use `min_probability_change_pct` to set the minimum move (e.g. `10` for 10%). Use `window_secs` to observe moves within a specific time window (e.g. `60` for 60 seconds). Use `spike_direction` (`\"up\"` | `\"down\"` | `\"both\"`) — defaults to `\"up\"` when not provided. Filter by `position_ids` or `outcomes` to narrow scope.\n\n**Credits cost:** 2 per delivered alert.\n\n**Applicable filters:** `position_ids`, `condition_ids`, `event_slugs`, `outcomes`, `min_probability_change_pct`, `spike_direction`, `window_secs`, `exclude_shortterm_markets`\n\nConnection: `wss://api.struct.to/ws/alerts?api-key=` — all alert channels share the same physical endpoint.", + "servers": [ + { + "$ref": "#/servers/alerts" + } + ], + "tags": [ + { + "name": "position" + } + ], + "messages": { + "subscribe": { + "$ref": "#/components/messages/WsAlertProbabilitySpikeSubscribe" + }, + "unsubscribe": { + "$ref": "#/components/messages/WsAlertProbabilitySpikeUnsubscribe" + }, + "event": { + "$ref": "#/components/messages/WsAlertProbabilitySpikeEvent" + }, + "subscribed": { + "$ref": "#/components/messages/WsAlertSubscribed" + }, + "unsubscribed": { + "$ref": "#/components/messages/WsAlertUnsubscribed" + }, + "error": { + "$ref": "#/components/messages/WsAlertError" + } + } + }, + "ws_alerts.price_spike": { + "address": "/ws/alerts", + "title": "Price Spike", + "summary": "Real-time `price_spike` alert subscription", + "description": "Fired when a position's price moves significantly. Use `min_price_change_pct` to set the minimum move (e.g. `10` for 10%). Use `window_secs` to observe moves within a specific time window. Use `spike_direction` (`\"up\"` | `\"down\"` | `\"both\"`) — defaults to `\"up\"` when not provided. Filter by `position_ids` or `outcomes` to narrow scope.\n\n**Credits cost:** 2 per delivered alert.\n\n**Applicable filters:** `position_ids`, `condition_ids`, `event_slugs`, `outcomes`, `min_price_change_pct`, `spike_direction`, `window_secs`, `exclude_shortterm_markets`\n\nConnection: `wss://api.struct.to/ws/alerts?api-key=` — all alert channels share the same physical endpoint.", + "servers": [ + { + "$ref": "#/servers/alerts" + } + ], + "tags": [ + { + "name": "position" + } + ], + "messages": { + "subscribe": { + "$ref": "#/components/messages/WsAlertPriceSpikeSubscribe" + }, + "unsubscribe": { + "$ref": "#/components/messages/WsAlertPriceSpikeUnsubscribe" + }, + "event": { + "$ref": "#/components/messages/WsAlertPriceSpikeEvent" + }, + "subscribed": { + "$ref": "#/components/messages/WsAlertSubscribed" + }, + "unsubscribed": { + "$ref": "#/components/messages/WsAlertUnsubscribed" + }, + "error": { + "$ref": "#/components/messages/WsAlertError" + } + } + }, + "ws_alerts.market_volume_spike": { + "address": "/ws/alerts", + "title": "Market Volume Spike", + "summary": "Real-time `market_volume_spike` alert subscription", + "description": "Fired when a market's trading volume grows by a multiple of `spike_ratio` within a timeframe. Requires `spike_ratio` (> 1.0, e.g. `2.0` fires when volume doubles). Optional `window_secs` sets the observation window in seconds (max 600). Optional `timeframes` — valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `1d`, `24h`, `7d`, `30d`. Optional `condition_ids` restricts to specific markets.\n\n**Credits cost:** 2 per delivered alert.\n\n**Applicable filters:** `spike_ratio`, `window_secs`, `condition_ids`, `timeframes`\n\nConnection: `wss://api.struct.to/ws/alerts?api-key=` — all alert channels share the same physical endpoint.", + "servers": [ + { + "$ref": "#/servers/alerts" + } + ], + "tags": [ + { + "name": "market" + } + ], + "messages": { + "subscribe": { + "$ref": "#/components/messages/WsAlertMarketVolumeSpikeSubscribe" + }, + "unsubscribe": { + "$ref": "#/components/messages/WsAlertMarketVolumeSpikeUnsubscribe" + }, + "event": { + "$ref": "#/components/messages/WsAlertMarketVolumeSpikeEvent" + }, + "subscribed": { + "$ref": "#/components/messages/WsAlertSubscribed" + }, + "unsubscribed": { + "$ref": "#/components/messages/WsAlertUnsubscribed" + }, + "error": { + "$ref": "#/components/messages/WsAlertError" + } + } + }, + "ws_alerts.event_volume_spike": { + "address": "/ws/alerts", + "title": "Event Volume Spike", + "summary": "Real-time `event_volume_spike` alert subscription", + "description": "Fired when an event's aggregated trading volume grows by a multiple of `spike_ratio` within a timeframe. Requires `spike_ratio` (> 1.0, e.g. `2.0` fires when volume doubles). Optional `window_secs` sets the observation window in seconds (max 600). Optional `timeframes` and `event_slugs` to narrow scope.\n\n**Credits cost:** 2 per delivered alert.\n\n**Applicable filters:** `spike_ratio`, `window_secs`, `event_slugs`, `timeframes`, `exclude_shortterm_markets`\n\nConnection: `wss://api.struct.to/ws/alerts?api-key=` — all alert channels share the same physical endpoint.", + "servers": [ + { + "$ref": "#/servers/alerts" + } + ], + "tags": [ + { + "name": "event" + } + ], + "messages": { + "subscribe": { + "$ref": "#/components/messages/WsAlertEventVolumeSpikeSubscribe" + }, + "unsubscribe": { + "$ref": "#/components/messages/WsAlertEventVolumeSpikeUnsubscribe" + }, + "event": { + "$ref": "#/components/messages/WsAlertEventVolumeSpikeEvent" + }, + "subscribed": { + "$ref": "#/components/messages/WsAlertSubscribed" + }, + "unsubscribed": { + "$ref": "#/components/messages/WsAlertUnsubscribed" + }, + "error": { + "$ref": "#/components/messages/WsAlertError" + } + } + }, + "ws_alerts.position_volume_spike": { + "address": "/ws/alerts", + "title": "Position Volume Spike", + "summary": "Real-time `position_volume_spike` alert subscription", + "description": "Fired when a position's trading volume grows by a multiple of `spike_ratio` within a timeframe. Requires `spike_ratio` (> 1.0, e.g. `2.0` fires when volume doubles). Optional `window_secs` sets the observation window in seconds (max 600). Optional `position_ids`, `condition_ids`, `outcomes`, and `timeframes` to narrow scope.\n\n**Credits cost:** 2 per delivered alert.\n\n**Applicable filters:** `spike_ratio`, `window_secs`, `position_ids`, `condition_ids`, `outcomes`, `timeframes`\n\nConnection: `wss://api.struct.to/ws/alerts?api-key=` — all alert channels share the same physical endpoint.", + "servers": [ + { + "$ref": "#/servers/alerts" + } + ], + "tags": [ + { + "name": "position" + } + ], + "messages": { + "subscribe": { + "$ref": "#/components/messages/WsAlertPositionVolumeSpikeSubscribe" + }, + "unsubscribe": { + "$ref": "#/components/messages/WsAlertPositionVolumeSpikeUnsubscribe" + }, + "event": { + "$ref": "#/components/messages/WsAlertPositionVolumeSpikeEvent" + }, + "subscribed": { + "$ref": "#/components/messages/WsAlertSubscribed" + }, + "unsubscribed": { + "$ref": "#/components/messages/WsAlertUnsubscribed" + }, + "error": { + "$ref": "#/components/messages/WsAlertError" + } + } + }, + "ws_alerts.close_to_bond": { + "address": "/ws/alerts", + "title": "Close To Bond", + "summary": "Real-time `close_to_bond` alert subscription", + "description": "Fired when a trade occurs at a near-certain-outcome price. **At least one of `min_probability` or `max_probability` is required.** Use `min_probability` (e.g. `0.95`) to trigger when YES is near-certain; use `max_probability` (e.g. `0.05`) for NO near-certain. Optional filters: `position_outcome_indices` — restrict by outcome index (`0` = Yes/Up, `1` = No); `condition_ids` — restrict to specific markets; `position_ids` — restrict to specific outcome tokens; `outcomes` — restrict by outcome name (e.g. `\"Yes\"`, `\"No\"`); `event_slugs` — restrict to specific events.\n\n**Credits cost:** 2 per delivered alert.\n\n**Applicable filters:** `min_probability`, `max_probability`, `condition_ids`, `position_ids`, `outcomes`, `position_outcome_indices`, `event_slugs`, `exclude_shortterm_markets`\n\nConnection: `wss://api.struct.to/ws/alerts?api-key=` — all alert channels share the same physical endpoint.", + "servers": [ + { + "$ref": "#/servers/alerts" + } + ], + "tags": [ + { + "name": "market" + } + ], + "messages": { + "subscribe": { + "$ref": "#/components/messages/WsAlertCloseToBondSubscribe" + }, + "unsubscribe": { + "$ref": "#/components/messages/WsAlertCloseToBondUnsubscribe" + }, + "event": { + "$ref": "#/components/messages/WsAlertCloseToBondEvent" + }, + "subscribed": { + "$ref": "#/components/messages/WsAlertSubscribed" + }, + "unsubscribed": { + "$ref": "#/components/messages/WsAlertUnsubscribed" + }, + "error": { + "$ref": "#/components/messages/WsAlertError" + } + } + }, + "ws_alerts.market_created": { + "address": "/ws/alerts", + "title": "Market Created", + "summary": "Real-time `market_created` alert subscription", + "description": "Fired when a new prediction market is created on Polymarket. Filterable by `tags` and `event_slugs`.\n\n**Credits cost:** 1 per delivered alert.\n\n**Applicable filters:** `event_slugs`, `tags`, `exclude_shortterm_markets`\n\nConnection: `wss://api.struct.to/ws/alerts?api-key=` — all alert channels share the same physical endpoint.", + "servers": [ + { + "$ref": "#/servers/alerts" + } + ], + "tags": [ + { + "name": "market" + } + ], + "messages": { + "subscribe": { + "$ref": "#/components/messages/WsAlertMarketCreatedSubscribe" + }, + "unsubscribe": { + "$ref": "#/components/messages/WsAlertMarketCreatedUnsubscribe" + }, + "event": { + "$ref": "#/components/messages/WsAlertMarketCreatedEvent" + }, + "subscribed": { + "$ref": "#/components/messages/WsAlertSubscribed" + }, + "unsubscribed": { + "$ref": "#/components/messages/WsAlertUnsubscribed" + }, + "error": { + "$ref": "#/components/messages/WsAlertError" + } + } + }, + "ws_alerts.asset_price_tick": { + "address": "/ws/alerts", + "title": "Asset Price Tick", + "summary": "Real-time `asset_price_tick` alert subscription", + "description": "Fired when the price of a tracked crypto asset updates (BTC, ETH, SOL, XRP, DOGE, BNB, HYPE). Use `asset_symbols` to restrict to specific assets (empty = all).\n\n**Credits cost:** 1 per delivered alert.\n\n**Applicable filters:** `asset_symbols`\n\nConnection: `wss://api.struct.to/ws/alerts?api-key=` — all alert channels share the same physical endpoint.", + "servers": [ + { + "$ref": "#/servers/alerts" + } + ], + "tags": [ + { + "name": "assets" + } + ], + "messages": { + "subscribe": { + "$ref": "#/components/messages/WsAlertAssetPriceTickSubscribe" + }, + "unsubscribe": { + "$ref": "#/components/messages/WsAlertAssetPriceTickUnsubscribe" + }, + "event": { + "$ref": "#/components/messages/WsAlertAssetPriceTickEvent" + }, + "subscribed": { + "$ref": "#/components/messages/WsAlertSubscribed" + }, + "unsubscribed": { + "$ref": "#/components/messages/WsAlertUnsubscribed" + }, + "error": { + "$ref": "#/components/messages/WsAlertError" + } + } + }, + "ws_alerts.asset_price_window_update": { + "address": "/ws/alerts", + "title": "Asset Price Window Update", + "summary": "Real-time `asset_price_window_update` alert subscription", + "description": "Fired at the start and end of each price candle for tracked crypto assets (BTC, ETH, SOL, XRP, DOGE, BNB, HYPE). Payload includes `update_type` (`\"open\"` or `\"close\"`) indicating whether the candle is opening or closing. Use `asset_symbols` to restrict to specific assets. Use `timeframes` to restrict to specific candle sizes — valid values: `\"5m\"`, `\"15m\"`, `\"1h\"`, `\"4h\"`, `\"1d\"`, `\"24h\"`.\n\n**Credits cost:** 1 per delivered alert.\n\n**Applicable filters:** `asset_symbols`, `timeframes`\n\nConnection: `wss://api.struct.to/ws/alerts?api-key=` — all alert channels share the same physical endpoint.", + "servers": [ + { + "$ref": "#/servers/alerts" + } + ], + "tags": [ + { + "name": "assets" + } + ], + "messages": { + "subscribe": { + "$ref": "#/components/messages/WsAlertAssetPriceWindowUpdateSubscribe" + }, + "unsubscribe": { + "$ref": "#/components/messages/WsAlertAssetPriceWindowUpdateUnsubscribe" + }, + "event": { + "$ref": "#/components/messages/WsAlertAssetPriceWindowUpdateEvent" + }, + "subscribed": { + "$ref": "#/components/messages/WsAlertSubscribed" + }, + "unsubscribed": { + "$ref": "#/components/messages/WsAlertUnsubscribed" + }, + "error": { + "$ref": "#/components/messages/WsAlertError" + } + } + } + }, + "operations": { + "subscribeTraderFirstTrade": { + "action": "send", + "channel": { + "$ref": "#/channels/ws_alerts.trader_first_trade" + }, + "title": "Subscribe — First Trade", + "summary": "Subscribe to `trader_first_trade` alerts", + "description": "Fired when a tracked trader executes their first trade on Polymarket", + "tags": [ + { + "name": "trader" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.trader_first_trade/messages/subscribe" + } + ] + }, + "unsubscribeTraderFirstTrade": { + "action": "send", + "channel": { + "$ref": "#/channels/ws_alerts.trader_first_trade" + }, + "title": "Unsubscribe — First Trade", + "summary": "Unsubscribe from `trader_first_trade` alerts", + "description": "Stop receiving `trader_first_trade` alerts. Filter fields must match the original subscription exactly.", + "tags": [ + { + "name": "trader" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.trader_first_trade/messages/unsubscribe" + } + ] + }, + "receiveTraderFirstTrade": { + "action": "receive", + "channel": { + "$ref": "#/channels/ws_alerts.trader_first_trade" + }, + "title": "Event — First Trade", + "summary": "Receive `trader_first_trade` alerts", + "description": "Fired when a tracked trader executes their first trade on Polymarket\n\n**Credits cost:** 1 per delivered alert.", + "tags": [ + { + "name": "trader" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.trader_first_trade/messages/event" + } + ] + }, + "subscribeTraderNewMarket": { + "action": "send", + "channel": { + "$ref": "#/channels/ws_alerts.trader_new_market" + }, + "title": "Subscribe — New Market Entry", + "summary": "Subscribe to `trader_new_market` alerts", + "description": "Fired when a trader places their first trade in a specific market/condition (fires once per trader+market pair)", + "tags": [ + { + "name": "trader" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.trader_new_market/messages/subscribe" + } + ] + }, + "unsubscribeTraderNewMarket": { + "action": "send", + "channel": { + "$ref": "#/channels/ws_alerts.trader_new_market" + }, + "title": "Unsubscribe — New Market Entry", + "summary": "Unsubscribe from `trader_new_market` alerts", + "description": "Stop receiving `trader_new_market` alerts. Filter fields must match the original subscription exactly.", + "tags": [ + { + "name": "trader" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.trader_new_market/messages/unsubscribe" + } + ] + }, + "receiveTraderNewMarket": { + "action": "receive", + "channel": { + "$ref": "#/channels/ws_alerts.trader_new_market" + }, + "title": "Event — New Market Entry", + "summary": "Receive `trader_new_market` alerts", + "description": "Fired when a trader places their first trade in a specific market/condition (fires once per trader+market pair)\n\n**Credits cost:** 1 per delivered alert.", + "tags": [ + { + "name": "trader" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.trader_new_market/messages/event" + } + ] + }, + "subscribeTraderWhaleTrade": { + "action": "send", + "channel": { + "$ref": "#/channels/ws_alerts.trader_whale_trade" + }, + "title": "Subscribe — Whale Trade", + "summary": "Subscribe to `trader_whale_trade` alerts", + "description": "Fired when a trade meets the configured criteria. Use `min_usd_value` to filter by minimum trade size (optional, defaults to 0 — matches all trades), and `min_probability`/`max_probability` to restrict to a probability range.", + "tags": [ + { + "name": "trader" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.trader_whale_trade/messages/subscribe" + } + ] + }, + "unsubscribeTraderWhaleTrade": { + "action": "send", + "channel": { + "$ref": "#/channels/ws_alerts.trader_whale_trade" + }, + "title": "Unsubscribe — Whale Trade", + "summary": "Unsubscribe from `trader_whale_trade` alerts", + "description": "Stop receiving `trader_whale_trade` alerts. Filter fields must match the original subscription exactly.", + "tags": [ + { + "name": "trader" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.trader_whale_trade/messages/unsubscribe" + } + ] + }, + "receiveTraderWhaleTrade": { + "action": "receive", + "channel": { + "$ref": "#/channels/ws_alerts.trader_whale_trade" + }, + "title": "Event — Whale Trade", + "summary": "Receive `trader_whale_trade` alerts", + "description": "Fired when a trade meets the configured criteria. Use `min_usd_value` to filter by minimum trade size (optional, defaults to 0 — matches all trades), and `min_probability`/`max_probability` to restrict to a probability range.\n\n**Credits cost:** 2 per delivered alert.", + "tags": [ + { + "name": "trader" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.trader_whale_trade/messages/event" + } + ] + }, + "subscribeTraderNewTrade": { + "action": "send", + "channel": { + "$ref": "#/channels/ws_alerts.trader_new_trade" + }, + "title": "Subscribe — New Trade", + "summary": "Subscribe to `trader_new_trade` alerts", + "description": "Fired on every order-filled trade. Use `wallet_addresses` to watch specific traders, `min_usd_value` to filter by size, and `min_probability`/`max_probability` to restrict to a probability range.", + "tags": [ + { + "name": "trader" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.trader_new_trade/messages/subscribe" + } + ] + }, + "unsubscribeTraderNewTrade": { + "action": "send", + "channel": { + "$ref": "#/channels/ws_alerts.trader_new_trade" + }, + "title": "Unsubscribe — New Trade", + "summary": "Unsubscribe from `trader_new_trade` alerts", + "description": "Stop receiving `trader_new_trade` alerts. Filter fields must match the original subscription exactly.", + "tags": [ + { + "name": "trader" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.trader_new_trade/messages/unsubscribe" + } + ] + }, + "receiveTraderNewTrade": { + "action": "receive", + "channel": { + "$ref": "#/channels/ws_alerts.trader_new_trade" + }, + "title": "Event — New Trade", + "summary": "Receive `trader_new_trade` alerts", + "description": "Fired on every order-filled trade. Use `wallet_addresses` to watch specific traders, `min_usd_value` to filter by size, and `min_probability`/`max_probability` to restrict to a probability range.\n\n**Credits cost:** 2 per delivered alert.", + "tags": [ + { + "name": "trader" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.trader_new_trade/messages/event" + } + ] + }, + "subscribeTraderGlobalPnl": { + "action": "send", + "channel": { + "$ref": "#/channels/ws_alerts.trader_global_pnl" + }, + "title": "Subscribe — Global PnL", + "summary": "Subscribe to `trader_global_pnl` alerts", + "description": "Fired when a trader's global PnL crosses a configured threshold", + "tags": [ + { + "name": "trader" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.trader_global_pnl/messages/subscribe" + } + ] + }, + "unsubscribeTraderGlobalPnl": { + "action": "send", + "channel": { + "$ref": "#/channels/ws_alerts.trader_global_pnl" + }, + "title": "Unsubscribe — Global PnL", + "summary": "Unsubscribe from `trader_global_pnl` alerts", + "description": "Stop receiving `trader_global_pnl` alerts. Filter fields must match the original subscription exactly.", + "tags": [ + { + "name": "trader" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.trader_global_pnl/messages/unsubscribe" + } + ] + }, + "receiveTraderGlobalPnl": { + "action": "receive", + "channel": { + "$ref": "#/channels/ws_alerts.trader_global_pnl" + }, + "title": "Event — Global PnL", + "summary": "Receive `trader_global_pnl` alerts", + "description": "Fired when a trader's global PnL crosses a configured threshold\n\n**Credits cost:** 1 per delivered alert.", + "tags": [ + { + "name": "trader" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.trader_global_pnl/messages/event" + } + ] + }, + "subscribeTraderMarketPnl": { + "action": "send", + "channel": { + "$ref": "#/channels/ws_alerts.trader_market_pnl" + }, + "title": "Subscribe — Market PnL", + "summary": "Subscribe to `trader_market_pnl` alerts", + "description": "Fired when a trader's market-level PnL crosses a configured threshold", + "tags": [ + { + "name": "trader" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.trader_market_pnl/messages/subscribe" + } + ] + }, + "unsubscribeTraderMarketPnl": { + "action": "send", + "channel": { + "$ref": "#/channels/ws_alerts.trader_market_pnl" + }, + "title": "Unsubscribe — Market PnL", + "summary": "Unsubscribe from `trader_market_pnl` alerts", + "description": "Stop receiving `trader_market_pnl` alerts. Filter fields must match the original subscription exactly.", + "tags": [ + { + "name": "trader" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.trader_market_pnl/messages/unsubscribe" + } + ] + }, + "receiveTraderMarketPnl": { + "action": "receive", + "channel": { + "$ref": "#/channels/ws_alerts.trader_market_pnl" + }, + "title": "Event — Market PnL", + "summary": "Receive `trader_market_pnl` alerts", + "description": "Fired when a trader's market-level PnL crosses a configured threshold\n\n**Credits cost:** 1 per delivered alert.", + "tags": [ + { + "name": "trader" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.trader_market_pnl/messages/event" + } + ] + }, + "subscribeTraderEventPnl": { + "action": "send", + "channel": { + "$ref": "#/channels/ws_alerts.trader_event_pnl" + }, + "title": "Subscribe — Event PnL", + "summary": "Subscribe to `trader_event_pnl` alerts", + "description": "Fired when a trader's event-level PnL crosses a configured threshold", + "tags": [ + { + "name": "trader" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.trader_event_pnl/messages/subscribe" + } + ] + }, + "unsubscribeTraderEventPnl": { + "action": "send", + "channel": { + "$ref": "#/channels/ws_alerts.trader_event_pnl" + }, + "title": "Unsubscribe — Event PnL", + "summary": "Unsubscribe from `trader_event_pnl` alerts", + "description": "Stop receiving `trader_event_pnl` alerts. Filter fields must match the original subscription exactly.", + "tags": [ + { + "name": "trader" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.trader_event_pnl/messages/unsubscribe" + } + ] + }, + "receiveTraderEventPnl": { + "action": "receive", + "channel": { + "$ref": "#/channels/ws_alerts.trader_event_pnl" + }, + "title": "Event — Event PnL", + "summary": "Receive `trader_event_pnl` alerts", + "description": "Fired when a trader's event-level PnL crosses a configured threshold\n\n**Credits cost:** 1 per delivered alert.", + "tags": [ + { + "name": "trader" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.trader_event_pnl/messages/event" + } + ] + }, + "subscribeConditionMetrics": { + "action": "send", + "channel": { + "$ref": "#/channels/ws_alerts.condition_metrics" + }, + "title": "Subscribe — Market Metrics", + "summary": "Subscribe to `condition_metrics` alerts", + "description": "Fired when a market's volume or transaction metrics cross a configured threshold. Use `timeframes` to restrict to specific windows (valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`).", + "tags": [ + { + "name": "market" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.condition_metrics/messages/subscribe" + } + ] + }, + "unsubscribeConditionMetrics": { + "action": "send", + "channel": { + "$ref": "#/channels/ws_alerts.condition_metrics" + }, + "title": "Unsubscribe — Market Metrics", + "summary": "Unsubscribe from `condition_metrics` alerts", + "description": "Stop receiving `condition_metrics` alerts. Filter fields must match the original subscription exactly.", + "tags": [ + { + "name": "market" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.condition_metrics/messages/unsubscribe" + } + ] + }, + "receiveConditionMetrics": { + "action": "receive", + "channel": { + "$ref": "#/channels/ws_alerts.condition_metrics" + }, + "title": "Event — Market Metrics", + "summary": "Receive `condition_metrics` alerts", + "description": "Fired when a market's volume or transaction metrics cross a configured threshold. Use `timeframes` to restrict to specific windows (valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`).\n\n**Credits cost:** 1 per delivered alert.", + "tags": [ + { + "name": "market" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.condition_metrics/messages/event" + } + ] + }, + "subscribeEventMetrics": { + "action": "send", + "channel": { + "$ref": "#/channels/ws_alerts.event_metrics" + }, + "title": "Subscribe — Event Metrics", + "summary": "Subscribe to `event_metrics` alerts", + "description": "Fired when an event's volume or transaction metrics cross a configured threshold. Use `timeframes` to restrict to specific windows (valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`).", + "tags": [ + { + "name": "event" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.event_metrics/messages/subscribe" + } + ] + }, + "unsubscribeEventMetrics": { + "action": "send", + "channel": { + "$ref": "#/channels/ws_alerts.event_metrics" + }, + "title": "Unsubscribe — Event Metrics", + "summary": "Unsubscribe from `event_metrics` alerts", + "description": "Stop receiving `event_metrics` alerts. Filter fields must match the original subscription exactly.", + "tags": [ + { + "name": "event" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.event_metrics/messages/unsubscribe" + } + ] + }, + "receiveEventMetrics": { + "action": "receive", + "channel": { + "$ref": "#/channels/ws_alerts.event_metrics" + }, + "title": "Event — Event Metrics", + "summary": "Receive `event_metrics` alerts", + "description": "Fired when an event's volume or transaction metrics cross a configured threshold. Use `timeframes` to restrict to specific windows (valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`).\n\n**Credits cost:** 1 per delivered alert.", + "tags": [ + { + "name": "event" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.event_metrics/messages/event" + } + ] + }, + "subscribePositionMetrics": { + "action": "send", + "channel": { + "$ref": "#/channels/ws_alerts.position_metrics" + }, + "title": "Subscribe — Position Metrics", + "summary": "Subscribe to `position_metrics` alerts", + "description": "Fired when a position's volume or transaction metrics cross a configured threshold. Use `timeframes` to restrict to specific windows (valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`).", + "tags": [ + { + "name": "position" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.position_metrics/messages/subscribe" + } + ] + }, + "unsubscribePositionMetrics": { + "action": "send", + "channel": { + "$ref": "#/channels/ws_alerts.position_metrics" + }, + "title": "Unsubscribe — Position Metrics", + "summary": "Unsubscribe from `position_metrics` alerts", + "description": "Stop receiving `position_metrics` alerts. Filter fields must match the original subscription exactly.", + "tags": [ + { + "name": "position" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.position_metrics/messages/unsubscribe" + } + ] + }, + "receivePositionMetrics": { + "action": "receive", + "channel": { + "$ref": "#/channels/ws_alerts.position_metrics" + }, + "title": "Event — Position Metrics", + "summary": "Receive `position_metrics` alerts", + "description": "Fired when a position's volume or transaction metrics cross a configured threshold. Use `timeframes` to restrict to specific windows (valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`).\n\n**Credits cost:** 1 per delivered alert.", + "tags": [ + { + "name": "position" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.position_metrics/messages/event" + } + ] + }, + "subscribeMarketVolumeMilestone": { + "action": "send", + "channel": { + "$ref": "#/channels/ws_alerts.market_volume_milestone" + }, + "title": "Subscribe — Market Volume Milestone", + "summary": "Subscribe to `market_volume_milestone` alerts", + "description": "Fired when a market's trading volume crosses a milestone threshold in the specified timeframe. **`timeframes` is required** (e.g. `[\"1h\", \"24h\"]`) — valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`. Optional `milestone_amounts` restricts to specific USD thresholds (e.g. `[10000, 100000]`). Optional `condition_ids` restricts to specific markets.", + "tags": [ + { + "name": "market" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.market_volume_milestone/messages/subscribe" + } + ] + }, + "unsubscribeMarketVolumeMilestone": { + "action": "send", + "channel": { + "$ref": "#/channels/ws_alerts.market_volume_milestone" + }, + "title": "Unsubscribe — Market Volume Milestone", + "summary": "Unsubscribe from `market_volume_milestone` alerts", + "description": "Stop receiving `market_volume_milestone` alerts. Filter fields must match the original subscription exactly.", + "tags": [ + { + "name": "market" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.market_volume_milestone/messages/unsubscribe" + } + ] + }, + "receiveMarketVolumeMilestone": { + "action": "receive", + "channel": { + "$ref": "#/channels/ws_alerts.market_volume_milestone" + }, + "title": "Event — Market Volume Milestone", + "summary": "Receive `market_volume_milestone` alerts", + "description": "Fired when a market's trading volume crosses a milestone threshold in the specified timeframe. **`timeframes` is required** (e.g. `[\"1h\", \"24h\"]`) — valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`. Optional `milestone_amounts` restricts to specific USD thresholds (e.g. `[10000, 100000]`). Optional `condition_ids` restricts to specific markets.\n\n**Credits cost:** 2 per delivered alert.", + "tags": [ + { + "name": "market" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.market_volume_milestone/messages/event" + } + ] + }, + "subscribeEventVolumeMilestone": { + "action": "send", + "channel": { + "$ref": "#/channels/ws_alerts.event_volume_milestone" + }, + "title": "Subscribe — Event Volume Milestone", + "summary": "Subscribe to `event_volume_milestone` alerts", + "description": "Fired when an event's trading volume crosses a milestone threshold in the specified timeframe. **`timeframes` is required** (e.g. `[\"1h\", \"24h\"]`) — valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`. Optional `milestone_amounts` restricts to specific USD thresholds. Optional `event_slugs` restricts to specific events.", + "tags": [ + { + "name": "event" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.event_volume_milestone/messages/subscribe" + } + ] + }, + "unsubscribeEventVolumeMilestone": { + "action": "send", + "channel": { + "$ref": "#/channels/ws_alerts.event_volume_milestone" + }, + "title": "Unsubscribe — Event Volume Milestone", + "summary": "Unsubscribe from `event_volume_milestone` alerts", + "description": "Stop receiving `event_volume_milestone` alerts. Filter fields must match the original subscription exactly.", + "tags": [ + { + "name": "event" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.event_volume_milestone/messages/unsubscribe" + } + ] + }, + "receiveEventVolumeMilestone": { + "action": "receive", + "channel": { + "$ref": "#/channels/ws_alerts.event_volume_milestone" + }, + "title": "Event — Event Volume Milestone", + "summary": "Receive `event_volume_milestone` alerts", + "description": "Fired when an event's trading volume crosses a milestone threshold in the specified timeframe. **`timeframes` is required** (e.g. `[\"1h\", \"24h\"]`) — valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`. Optional `milestone_amounts` restricts to specific USD thresholds. Optional `event_slugs` restricts to specific events.\n\n**Credits cost:** 2 per delivered alert.", + "tags": [ + { + "name": "event" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.event_volume_milestone/messages/event" + } + ] + }, + "subscribePositionVolumeMilestone": { + "action": "send", + "channel": { + "$ref": "#/channels/ws_alerts.position_volume_milestone" + }, + "title": "Subscribe — Position Volume Milestone", + "summary": "Subscribe to `position_volume_milestone` alerts", + "description": "Fired when a position's trading volume crosses a milestone threshold in the specified timeframe. **`timeframes` is required** (e.g. `[\"1h\", \"24h\"]`) — valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`. Optional `milestone_amounts` restricts to specific USD thresholds. Optional `position_ids` or `condition_ids` restrict to specific positions/markets.", + "tags": [ + { + "name": "position" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.position_volume_milestone/messages/subscribe" + } + ] + }, + "unsubscribePositionVolumeMilestone": { + "action": "send", + "channel": { + "$ref": "#/channels/ws_alerts.position_volume_milestone" + }, + "title": "Unsubscribe — Position Volume Milestone", + "summary": "Unsubscribe from `position_volume_milestone` alerts", + "description": "Stop receiving `position_volume_milestone` alerts. Filter fields must match the original subscription exactly.", + "tags": [ + { + "name": "position" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.position_volume_milestone/messages/unsubscribe" + } + ] + }, + "receivePositionVolumeMilestone": { + "action": "receive", + "channel": { + "$ref": "#/channels/ws_alerts.position_volume_milestone" + }, + "title": "Event — Position Volume Milestone", + "summary": "Receive `position_volume_milestone` alerts", + "description": "Fired when a position's trading volume crosses a milestone threshold in the specified timeframe. **`timeframes` is required** (e.g. `[\"1h\", \"24h\"]`) — valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`. Optional `milestone_amounts` restricts to specific USD thresholds. Optional `position_ids` or `condition_ids` restrict to specific positions/markets.\n\n**Credits cost:** 2 per delivered alert.", + "tags": [ + { + "name": "position" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.position_volume_milestone/messages/event" + } + ] + }, + "subscribeProbabilitySpike": { + "action": "send", + "channel": { + "$ref": "#/channels/ws_alerts.probability_spike" + }, + "title": "Subscribe — Probability Spike", + "summary": "Subscribe to `probability_spike` alerts", + "description": "Fired when a position's probability moves significantly. Use `min_probability_change_pct` to set the minimum move (e.g. `10` for 10%). Use `window_secs` to observe moves within a specific time window (e.g. `60` for 60 seconds). Use `spike_direction` (`\"up\"` | `\"down\"` | `\"both\"`) — defaults to `\"up\"` when not provided. Filter by `position_ids` or `outcomes` to narrow scope.", + "tags": [ + { + "name": "position" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.probability_spike/messages/subscribe" + } + ] + }, + "unsubscribeProbabilitySpike": { + "action": "send", + "channel": { + "$ref": "#/channels/ws_alerts.probability_spike" + }, + "title": "Unsubscribe — Probability Spike", + "summary": "Unsubscribe from `probability_spike` alerts", + "description": "Stop receiving `probability_spike` alerts. Filter fields must match the original subscription exactly.", + "tags": [ + { + "name": "position" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.probability_spike/messages/unsubscribe" + } + ] + }, + "receiveProbabilitySpike": { + "action": "receive", + "channel": { + "$ref": "#/channels/ws_alerts.probability_spike" + }, + "title": "Event — Probability Spike", + "summary": "Receive `probability_spike` alerts", + "description": "Fired when a position's probability moves significantly. Use `min_probability_change_pct` to set the minimum move (e.g. `10` for 10%). Use `window_secs` to observe moves within a specific time window (e.g. `60` for 60 seconds). Use `spike_direction` (`\"up\"` | `\"down\"` | `\"both\"`) — defaults to `\"up\"` when not provided. Filter by `position_ids` or `outcomes` to narrow scope.\n\n**Credits cost:** 2 per delivered alert.", + "tags": [ + { + "name": "position" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.probability_spike/messages/event" + } + ] + }, + "subscribePriceSpike": { + "action": "send", + "channel": { + "$ref": "#/channels/ws_alerts.price_spike" + }, + "title": "Subscribe — Price Spike", + "summary": "Subscribe to `price_spike` alerts", + "description": "Fired when a position's price moves significantly. Use `min_price_change_pct` to set the minimum move (e.g. `10` for 10%). Use `window_secs` to observe moves within a specific time window. Use `spike_direction` (`\"up\"` | `\"down\"` | `\"both\"`) — defaults to `\"up\"` when not provided. Filter by `position_ids` or `outcomes` to narrow scope.", + "tags": [ + { + "name": "position" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.price_spike/messages/subscribe" + } + ] + }, + "unsubscribePriceSpike": { + "action": "send", + "channel": { + "$ref": "#/channels/ws_alerts.price_spike" + }, + "title": "Unsubscribe — Price Spike", + "summary": "Unsubscribe from `price_spike` alerts", + "description": "Stop receiving `price_spike` alerts. Filter fields must match the original subscription exactly.", + "tags": [ + { + "name": "position" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.price_spike/messages/unsubscribe" + } + ] + }, + "receivePriceSpike": { + "action": "receive", + "channel": { + "$ref": "#/channels/ws_alerts.price_spike" + }, + "title": "Event — Price Spike", + "summary": "Receive `price_spike` alerts", + "description": "Fired when a position's price moves significantly. Use `min_price_change_pct` to set the minimum move (e.g. `10` for 10%). Use `window_secs` to observe moves within a specific time window. Use `spike_direction` (`\"up\"` | `\"down\"` | `\"both\"`) — defaults to `\"up\"` when not provided. Filter by `position_ids` or `outcomes` to narrow scope.\n\n**Credits cost:** 2 per delivered alert.", + "tags": [ + { + "name": "position" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.price_spike/messages/event" + } + ] + }, + "subscribeMarketVolumeSpike": { + "action": "send", + "channel": { + "$ref": "#/channels/ws_alerts.market_volume_spike" + }, + "title": "Subscribe — Market Volume Spike", + "summary": "Subscribe to `market_volume_spike` alerts", + "description": "Fired when a market's trading volume grows by a multiple of `spike_ratio` within a timeframe. Requires `spike_ratio` (> 1.0, e.g. `2.0` fires when volume doubles). Optional `window_secs` sets the observation window in seconds (max 600). Optional `timeframes` — valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `1d`, `24h`, `7d`, `30d`. Optional `condition_ids` restricts to specific markets.", + "tags": [ + { + "name": "market" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.market_volume_spike/messages/subscribe" + } + ] + }, + "unsubscribeMarketVolumeSpike": { + "action": "send", + "channel": { + "$ref": "#/channels/ws_alerts.market_volume_spike" + }, + "title": "Unsubscribe — Market Volume Spike", + "summary": "Unsubscribe from `market_volume_spike` alerts", + "description": "Stop receiving `market_volume_spike` alerts. Filter fields must match the original subscription exactly.", + "tags": [ + { + "name": "market" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.market_volume_spike/messages/unsubscribe" + } + ] + }, + "receiveMarketVolumeSpike": { + "action": "receive", + "channel": { + "$ref": "#/channels/ws_alerts.market_volume_spike" + }, + "title": "Event — Market Volume Spike", + "summary": "Receive `market_volume_spike` alerts", + "description": "Fired when a market's trading volume grows by a multiple of `spike_ratio` within a timeframe. Requires `spike_ratio` (> 1.0, e.g. `2.0` fires when volume doubles). Optional `window_secs` sets the observation window in seconds (max 600). Optional `timeframes` — valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `1d`, `24h`, `7d`, `30d`. Optional `condition_ids` restricts to specific markets.\n\n**Credits cost:** 2 per delivered alert.", + "tags": [ + { + "name": "market" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.market_volume_spike/messages/event" + } + ] + }, + "subscribeEventVolumeSpike": { + "action": "send", + "channel": { + "$ref": "#/channels/ws_alerts.event_volume_spike" + }, + "title": "Subscribe — Event Volume Spike", + "summary": "Subscribe to `event_volume_spike` alerts", + "description": "Fired when an event's aggregated trading volume grows by a multiple of `spike_ratio` within a timeframe. Requires `spike_ratio` (> 1.0, e.g. `2.0` fires when volume doubles). Optional `window_secs` sets the observation window in seconds (max 600). Optional `timeframes` and `event_slugs` to narrow scope.", + "tags": [ + { + "name": "event" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.event_volume_spike/messages/subscribe" + } + ] + }, + "unsubscribeEventVolumeSpike": { + "action": "send", + "channel": { + "$ref": "#/channels/ws_alerts.event_volume_spike" + }, + "title": "Unsubscribe — Event Volume Spike", + "summary": "Unsubscribe from `event_volume_spike` alerts", + "description": "Stop receiving `event_volume_spike` alerts. Filter fields must match the original subscription exactly.", + "tags": [ + { + "name": "event" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.event_volume_spike/messages/unsubscribe" + } + ] + }, + "receiveEventVolumeSpike": { + "action": "receive", + "channel": { + "$ref": "#/channels/ws_alerts.event_volume_spike" + }, + "title": "Event — Event Volume Spike", + "summary": "Receive `event_volume_spike` alerts", + "description": "Fired when an event's aggregated trading volume grows by a multiple of `spike_ratio` within a timeframe. Requires `spike_ratio` (> 1.0, e.g. `2.0` fires when volume doubles). Optional `window_secs` sets the observation window in seconds (max 600). Optional `timeframes` and `event_slugs` to narrow scope.\n\n**Credits cost:** 2 per delivered alert.", + "tags": [ + { + "name": "event" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.event_volume_spike/messages/event" + } + ] + }, + "subscribePositionVolumeSpike": { + "action": "send", + "channel": { + "$ref": "#/channels/ws_alerts.position_volume_spike" + }, + "title": "Subscribe — Position Volume Spike", + "summary": "Subscribe to `position_volume_spike` alerts", + "description": "Fired when a position's trading volume grows by a multiple of `spike_ratio` within a timeframe. Requires `spike_ratio` (> 1.0, e.g. `2.0` fires when volume doubles). Optional `window_secs` sets the observation window in seconds (max 600). Optional `position_ids`, `condition_ids`, `outcomes`, and `timeframes` to narrow scope.", + "tags": [ + { + "name": "position" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.position_volume_spike/messages/subscribe" + } + ] + }, + "unsubscribePositionVolumeSpike": { + "action": "send", + "channel": { + "$ref": "#/channels/ws_alerts.position_volume_spike" + }, + "title": "Unsubscribe — Position Volume Spike", + "summary": "Unsubscribe from `position_volume_spike` alerts", + "description": "Stop receiving `position_volume_spike` alerts. Filter fields must match the original subscription exactly.", + "tags": [ + { + "name": "position" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.position_volume_spike/messages/unsubscribe" + } + ] + }, + "receivePositionVolumeSpike": { + "action": "receive", + "channel": { + "$ref": "#/channels/ws_alerts.position_volume_spike" + }, + "title": "Event — Position Volume Spike", + "summary": "Receive `position_volume_spike` alerts", + "description": "Fired when a position's trading volume grows by a multiple of `spike_ratio` within a timeframe. Requires `spike_ratio` (> 1.0, e.g. `2.0` fires when volume doubles). Optional `window_secs` sets the observation window in seconds (max 600). Optional `position_ids`, `condition_ids`, `outcomes`, and `timeframes` to narrow scope.\n\n**Credits cost:** 2 per delivered alert.", + "tags": [ + { + "name": "position" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.position_volume_spike/messages/event" + } + ] + }, + "subscribeCloseToBond": { + "action": "send", + "channel": { + "$ref": "#/channels/ws_alerts.close_to_bond" + }, + "title": "Subscribe — Close To Bond", + "summary": "Subscribe to `close_to_bond` alerts", + "description": "Fired when a trade occurs at a near-certain-outcome price. **At least one of `min_probability` or `max_probability` is required.** Use `min_probability` (e.g. `0.95`) to trigger when YES is near-certain; use `max_probability` (e.g. `0.05`) for NO near-certain. Optional filters: `position_outcome_indices` — restrict by outcome index (`0` = Yes/Up, `1` = No); `condition_ids` — restrict to specific markets; `position_ids` — restrict to specific outcome tokens; `outcomes` — restrict by outcome name (e.g. `\"Yes\"`, `\"No\"`); `event_slugs` — restrict to specific events.", + "tags": [ + { + "name": "market" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.close_to_bond/messages/subscribe" + } + ] + }, + "unsubscribeCloseToBond": { + "action": "send", + "channel": { + "$ref": "#/channels/ws_alerts.close_to_bond" + }, + "title": "Unsubscribe — Close To Bond", + "summary": "Unsubscribe from `close_to_bond` alerts", + "description": "Stop receiving `close_to_bond` alerts. Filter fields must match the original subscription exactly.", + "tags": [ + { + "name": "market" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.close_to_bond/messages/unsubscribe" + } + ] + }, + "receiveCloseToBond": { + "action": "receive", + "channel": { + "$ref": "#/channels/ws_alerts.close_to_bond" + }, + "title": "Event — Close To Bond", + "summary": "Receive `close_to_bond` alerts", + "description": "Fired when a trade occurs at a near-certain-outcome price. **At least one of `min_probability` or `max_probability` is required.** Use `min_probability` (e.g. `0.95`) to trigger when YES is near-certain; use `max_probability` (e.g. `0.05`) for NO near-certain. Optional filters: `position_outcome_indices` — restrict by outcome index (`0` = Yes/Up, `1` = No); `condition_ids` — restrict to specific markets; `position_ids` — restrict to specific outcome tokens; `outcomes` — restrict by outcome name (e.g. `\"Yes\"`, `\"No\"`); `event_slugs` — restrict to specific events.\n\n**Credits cost:** 2 per delivered alert.", + "tags": [ + { + "name": "market" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.close_to_bond/messages/event" + } + ] + }, + "subscribeMarketCreated": { + "action": "send", + "channel": { + "$ref": "#/channels/ws_alerts.market_created" + }, + "title": "Subscribe — Market Created", + "summary": "Subscribe to `market_created` alerts", + "description": "Fired when a new prediction market is created on Polymarket. Filterable by `tags` and `event_slugs`.", + "tags": [ + { + "name": "market" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.market_created/messages/subscribe" + } + ] + }, + "unsubscribeMarketCreated": { + "action": "send", + "channel": { + "$ref": "#/channels/ws_alerts.market_created" + }, + "title": "Unsubscribe — Market Created", + "summary": "Unsubscribe from `market_created` alerts", + "description": "Stop receiving `market_created` alerts. Filter fields must match the original subscription exactly.", + "tags": [ + { + "name": "market" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.market_created/messages/unsubscribe" + } + ] + }, + "receiveMarketCreated": { + "action": "receive", + "channel": { + "$ref": "#/channels/ws_alerts.market_created" + }, + "title": "Event — Market Created", + "summary": "Receive `market_created` alerts", + "description": "Fired when a new prediction market is created on Polymarket. Filterable by `tags` and `event_slugs`.\n\n**Credits cost:** 1 per delivered alert.", + "tags": [ + { + "name": "market" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.market_created/messages/event" + } + ] + }, + "subscribeAssetPriceTick": { + "action": "send", + "channel": { + "$ref": "#/channels/ws_alerts.asset_price_tick" + }, + "title": "Subscribe — Asset Price Tick", + "summary": "Subscribe to `asset_price_tick` alerts", + "description": "Fired when the price of a tracked crypto asset updates (BTC, ETH, SOL, XRP, DOGE, BNB, HYPE). Use `asset_symbols` to restrict to specific assets (empty = all).", + "tags": [ + { + "name": "assets" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.asset_price_tick/messages/subscribe" + } + ] + }, + "unsubscribeAssetPriceTick": { + "action": "send", + "channel": { + "$ref": "#/channels/ws_alerts.asset_price_tick" + }, + "title": "Unsubscribe — Asset Price Tick", + "summary": "Unsubscribe from `asset_price_tick` alerts", + "description": "Stop receiving `asset_price_tick` alerts. Filter fields must match the original subscription exactly.", + "tags": [ + { + "name": "assets" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.asset_price_tick/messages/unsubscribe" + } + ] + }, + "receiveAssetPriceTick": { + "action": "receive", + "channel": { + "$ref": "#/channels/ws_alerts.asset_price_tick" + }, + "title": "Event — Asset Price Tick", + "summary": "Receive `asset_price_tick` alerts", + "description": "Fired when the price of a tracked crypto asset updates (BTC, ETH, SOL, XRP, DOGE, BNB, HYPE). Use `asset_symbols` to restrict to specific assets (empty = all).\n\n**Credits cost:** 1 per delivered alert.", + "tags": [ + { + "name": "assets" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.asset_price_tick/messages/event" + } + ] + }, + "subscribeAssetPriceWindowUpdate": { + "action": "send", + "channel": { + "$ref": "#/channels/ws_alerts.asset_price_window_update" + }, + "title": "Subscribe — Asset Price Window Update", + "summary": "Subscribe to `asset_price_window_update` alerts", + "description": "Fired at the start and end of each price candle for tracked crypto assets (BTC, ETH, SOL, XRP, DOGE, BNB, HYPE). Payload includes `update_type` (`\"open\"` or `\"close\"`) indicating whether the candle is opening or closing. Use `asset_symbols` to restrict to specific assets. Use `timeframes` to restrict to specific candle sizes — valid values: `\"5m\"`, `\"15m\"`, `\"1h\"`, `\"4h\"`, `\"1d\"`, `\"24h\"`.", + "tags": [ + { + "name": "assets" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.asset_price_window_update/messages/subscribe" + } + ] + }, + "unsubscribeAssetPriceWindowUpdate": { + "action": "send", + "channel": { + "$ref": "#/channels/ws_alerts.asset_price_window_update" + }, + "title": "Unsubscribe — Asset Price Window Update", + "summary": "Unsubscribe from `asset_price_window_update` alerts", + "description": "Stop receiving `asset_price_window_update` alerts. Filter fields must match the original subscription exactly.", + "tags": [ + { + "name": "assets" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.asset_price_window_update/messages/unsubscribe" + } + ] + }, + "receiveAssetPriceWindowUpdate": { + "action": "receive", + "channel": { + "$ref": "#/channels/ws_alerts.asset_price_window_update" + }, + "title": "Event — Asset Price Window Update", + "summary": "Receive `asset_price_window_update` alerts", + "description": "Fired at the start and end of each price candle for tracked crypto assets (BTC, ETH, SOL, XRP, DOGE, BNB, HYPE). Payload includes `update_type` (`\"open\"` or `\"close\"`) indicating whether the candle is opening or closing. Use `asset_symbols` to restrict to specific assets. Use `timeframes` to restrict to specific candle sizes — valid values: `\"5m\"`, `\"15m\"`, `\"1h\"`, `\"4h\"`, `\"1d\"`, `\"24h\"`.\n\n**Credits cost:** 1 per delivered alert.", + "tags": [ + { + "name": "assets" + } + ], + "messages": [ + { + "$ref": "#/channels/ws_alerts.asset_price_window_update/messages/event" + } + ] + } + }, + "components": { + "messages": { + "WsAlertTraderFirstTradeSubscribe": { + "name": "WsAlertTraderFirstTradeSubscribe", + "title": "First Trade — Subscribe", + "summary": "Subscribe to `trader_first_trade` alerts", + "description": "Fired when a tracked trader executes their first trade on Polymarket\n\n**Credits cost:** 1 per delivered alert.\n\n**Applicable filters:** `wallet_addresses`, `min_usd_value`, `min_probability`, `max_probability`, `condition_ids`, `event_slugs`, `exclude_shortterm_markets`", + "tags": [ + { + "name": "trader" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertTraderFirstTradeSubscribeMessage" + } + }, + "WsAlertTraderFirstTradeUnsubscribe": { + "name": "WsAlertTraderFirstTradeUnsubscribe", + "title": "First Trade — Unsubscribe", + "summary": "Unsubscribe from `trader_first_trade` alerts", + "description": "Unsubscribe from `trader_first_trade` alerts. The filter fields must match the original subscription exactly.", + "tags": [ + { + "name": "trader" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertTraderFirstTradeUnsubscribeMessage" + } + }, + "WsAlertTraderFirstTradeEvent": { + "name": "WsAlertTraderFirstTradeEvent", + "title": "First Trade — Event", + "summary": "`trader_first_trade` alert pushed from server", + "description": "Fired when a tracked trader executes their first trade on Polymarket\n\n**Credits cost:** 1 per delivered alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "tags": [ + { + "name": "trader" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertTraderFirstTradeEvent" + } + }, + "WsAlertTraderNewMarketSubscribe": { + "name": "WsAlertTraderNewMarketSubscribe", + "title": "New Market Entry — Subscribe", + "summary": "Subscribe to `trader_new_market` alerts", + "description": "Fired when a trader places their first trade in a specific market/condition (fires once per trader+market pair)\n\n**Credits cost:** 1 per delivered alert.\n\n**Applicable filters:** `wallet_addresses`, `condition_ids`, `event_slugs`, `min_usd_value`, `min_probability`, `max_probability`, `exclude_shortterm_markets`", + "tags": [ + { + "name": "trader" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertTraderNewMarketSubscribeMessage" + } + }, + "WsAlertTraderNewMarketUnsubscribe": { + "name": "WsAlertTraderNewMarketUnsubscribe", + "title": "New Market Entry — Unsubscribe", + "summary": "Unsubscribe from `trader_new_market` alerts", + "description": "Unsubscribe from `trader_new_market` alerts. The filter fields must match the original subscription exactly.", + "tags": [ + { + "name": "trader" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertTraderNewMarketUnsubscribeMessage" + } + }, + "WsAlertTraderNewMarketEvent": { + "name": "WsAlertTraderNewMarketEvent", + "title": "New Market Entry — Event", + "summary": "`trader_new_market` alert pushed from server", + "description": "Fired when a trader places their first trade in a specific market/condition (fires once per trader+market pair)\n\n**Credits cost:** 1 per delivered alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "tags": [ + { + "name": "trader" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertTraderNewMarketEvent" + } + }, + "WsAlertTraderWhaleTradeSubscribe": { + "name": "WsAlertTraderWhaleTradeSubscribe", + "title": "Whale Trade — Subscribe", + "summary": "Subscribe to `trader_whale_trade` alerts", + "description": "Fired when a trade meets the configured criteria. Use `min_usd_value` to filter by minimum trade size (optional, defaults to 0 — matches all trades), and `min_probability`/`max_probability` to restrict to a probability range.\n\n**Credits cost:** 2 per delivered alert.\n\n**Applicable filters:** `wallet_addresses`, `min_usd_value`, `min_probability`, `max_probability`, `condition_ids`, `event_slugs`, `exclude_shortterm_markets`", + "tags": [ + { + "name": "trader" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertTraderWhaleTradeSubscribeMessage" + } + }, + "WsAlertTraderWhaleTradeUnsubscribe": { + "name": "WsAlertTraderWhaleTradeUnsubscribe", + "title": "Whale Trade — Unsubscribe", + "summary": "Unsubscribe from `trader_whale_trade` alerts", + "description": "Unsubscribe from `trader_whale_trade` alerts. The filter fields must match the original subscription exactly.", + "tags": [ + { + "name": "trader" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertTraderWhaleTradeUnsubscribeMessage" + } + }, + "WsAlertTraderWhaleTradeEvent": { + "name": "WsAlertTraderWhaleTradeEvent", + "title": "Whale Trade — Event", + "summary": "`trader_whale_trade` alert pushed from server", + "description": "Fired when a trade meets the configured criteria. Use `min_usd_value` to filter by minimum trade size (optional, defaults to 0 — matches all trades), and `min_probability`/`max_probability` to restrict to a probability range.\n\n**Credits cost:** 2 per delivered alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "tags": [ + { + "name": "trader" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertTraderWhaleTradeEvent" + } + }, + "WsAlertTraderNewTradeSubscribe": { + "name": "WsAlertTraderNewTradeSubscribe", + "title": "New Trade — Subscribe", + "summary": "Subscribe to `trader_new_trade` alerts", + "description": "Fired on every order-filled trade. Use `wallet_addresses` to watch specific traders, `min_usd_value` to filter by size, and `min_probability`/`max_probability` to restrict to a probability range.\n\n**Credits cost:** 2 per delivered alert.\n\n**Applicable filters:** `wallet_addresses`, `min_usd_value`, `min_probability`, `max_probability`, `condition_ids`, `event_slugs`, `exclude_shortterm_markets`", + "tags": [ + { + "name": "trader" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertTraderNewTradeSubscribeMessage" + } + }, + "WsAlertTraderNewTradeUnsubscribe": { + "name": "WsAlertTraderNewTradeUnsubscribe", + "title": "New Trade — Unsubscribe", + "summary": "Unsubscribe from `trader_new_trade` alerts", + "description": "Unsubscribe from `trader_new_trade` alerts. The filter fields must match the original subscription exactly.", + "tags": [ + { + "name": "trader" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertTraderNewTradeUnsubscribeMessage" + } + }, + "WsAlertTraderNewTradeEvent": { + "name": "WsAlertTraderNewTradeEvent", + "title": "New Trade — Event", + "summary": "`trader_new_trade` alert pushed from server", + "description": "Fired on every order-filled trade. Use `wallet_addresses` to watch specific traders, `min_usd_value` to filter by size, and `min_probability`/`max_probability` to restrict to a probability range.\n\n**Credits cost:** 2 per delivered alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "tags": [ + { + "name": "trader" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertTraderNewTradeEvent" + } + }, + "WsAlertTraderGlobalPnlSubscribe": { + "name": "WsAlertTraderGlobalPnlSubscribe", + "title": "Global PnL — Subscribe", + "summary": "Subscribe to `trader_global_pnl` alerts", + "description": "Fired when a trader's global PnL crosses a configured threshold\n\n**Credits cost:** 1 per delivered alert.\n\n**Applicable filters:** `traders`, `min_realized_pnl_usd`, `max_realized_pnl_usd`, `min_volume_usd`, `max_volume_usd`, `min_buy_usd`, `min_sell_volume_usd`, `min_win_rate`, `min_markets_traded`, `timeframes`", + "tags": [ + { + "name": "trader" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertTraderGlobalPnlSubscribeMessage" + } + }, + "WsAlertTraderGlobalPnlUnsubscribe": { + "name": "WsAlertTraderGlobalPnlUnsubscribe", + "title": "Global PnL — Unsubscribe", + "summary": "Unsubscribe from `trader_global_pnl` alerts", + "description": "Unsubscribe from `trader_global_pnl` alerts. The filter fields must match the original subscription exactly.", + "tags": [ + { + "name": "trader" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertTraderGlobalPnlUnsubscribeMessage" + } + }, + "WsAlertTraderGlobalPnlEvent": { + "name": "WsAlertTraderGlobalPnlEvent", + "title": "Global PnL — Event", + "summary": "`trader_global_pnl` alert pushed from server", + "description": "Fired when a trader's global PnL crosses a configured threshold\n\n**Credits cost:** 1 per delivered alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "tags": [ + { + "name": "trader" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertTraderGlobalPnlEvent" + } + }, + "WsAlertTraderMarketPnlSubscribe": { + "name": "WsAlertTraderMarketPnlSubscribe", + "title": "Market PnL — Subscribe", + "summary": "Subscribe to `trader_market_pnl` alerts", + "description": "Fired when a trader's market-level PnL crosses a configured threshold\n\n**Credits cost:** 1 per delivered alert.\n\n**Applicable filters:** `traders`, `condition_ids`, `event_slugs`, `min_realized_pnl_usd`, `max_realized_pnl_usd`, `min_volume_usd`, `max_volume_usd`, `min_buy_usd`, `min_sell_volume_usd`, `timeframes`, `exclude_shortterm_markets`", + "tags": [ + { + "name": "trader" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertTraderMarketPnlSubscribeMessage" + } + }, + "WsAlertTraderMarketPnlUnsubscribe": { + "name": "WsAlertTraderMarketPnlUnsubscribe", + "title": "Market PnL — Unsubscribe", + "summary": "Unsubscribe from `trader_market_pnl` alerts", + "description": "Unsubscribe from `trader_market_pnl` alerts. The filter fields must match the original subscription exactly.", + "tags": [ + { + "name": "trader" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertTraderMarketPnlUnsubscribeMessage" + } + }, + "WsAlertTraderMarketPnlEvent": { + "name": "WsAlertTraderMarketPnlEvent", + "title": "Market PnL — Event", + "summary": "`trader_market_pnl` alert pushed from server", + "description": "Fired when a trader's market-level PnL crosses a configured threshold\n\n**Credits cost:** 1 per delivered alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "tags": [ + { + "name": "trader" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertTraderMarketPnlEvent" + } + }, + "WsAlertTraderEventPnlSubscribe": { + "name": "WsAlertTraderEventPnlSubscribe", + "title": "Event PnL — Subscribe", + "summary": "Subscribe to `trader_event_pnl` alerts", + "description": "Fired when a trader's event-level PnL crosses a configured threshold\n\n**Credits cost:** 1 per delivered alert.\n\n**Applicable filters:** `traders`, `event_slugs`, `min_realized_pnl_usd`, `max_realized_pnl_usd`, `min_volume_usd`, `max_volume_usd`, `min_buy_usd`, `min_sell_volume_usd`, `min_markets_traded`, `timeframes`, `exclude_shortterm_markets`", + "tags": [ + { + "name": "trader" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertTraderEventPnlSubscribeMessage" + } + }, + "WsAlertTraderEventPnlUnsubscribe": { + "name": "WsAlertTraderEventPnlUnsubscribe", + "title": "Event PnL — Unsubscribe", + "summary": "Unsubscribe from `trader_event_pnl` alerts", + "description": "Unsubscribe from `trader_event_pnl` alerts. The filter fields must match the original subscription exactly.", + "tags": [ + { + "name": "trader" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertTraderEventPnlUnsubscribeMessage" + } + }, + "WsAlertTraderEventPnlEvent": { + "name": "WsAlertTraderEventPnlEvent", + "title": "Event PnL — Event", + "summary": "`trader_event_pnl` alert pushed from server", + "description": "Fired when a trader's event-level PnL crosses a configured threshold\n\n**Credits cost:** 1 per delivered alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "tags": [ + { + "name": "trader" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertTraderEventPnlEvent" + } + }, + "WsAlertConditionMetricsSubscribe": { + "name": "WsAlertConditionMetricsSubscribe", + "title": "Market Metrics — Subscribe", + "summary": "Subscribe to `condition_metrics` alerts", + "description": "Fired when a market's volume or transaction metrics cross a configured threshold. Use `timeframes` to restrict to specific windows (valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`).\n\n**Credits cost:** 1 per delivered alert.\n\n**Applicable filters:** `condition_ids`, `min_volume_usd`, `max_volume_usd`, `min_fees`, `min_txns`, `min_unique_traders`, `timeframes`", + "tags": [ + { + "name": "market" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertConditionMetricsSubscribeMessage" + } + }, + "WsAlertConditionMetricsUnsubscribe": { + "name": "WsAlertConditionMetricsUnsubscribe", + "title": "Market Metrics — Unsubscribe", + "summary": "Unsubscribe from `condition_metrics` alerts", + "description": "Unsubscribe from `condition_metrics` alerts. The filter fields must match the original subscription exactly.", + "tags": [ + { + "name": "market" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertConditionMetricsUnsubscribeMessage" + } + }, + "WsAlertConditionMetricsEvent": { + "name": "WsAlertConditionMetricsEvent", + "title": "Market Metrics — Event", + "summary": "`condition_metrics` alert pushed from server", + "description": "Fired when a market's volume or transaction metrics cross a configured threshold. Use `timeframes` to restrict to specific windows (valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`).\n\n**Credits cost:** 1 per delivered alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "tags": [ + { + "name": "market" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertConditionMetricsEvent" + } + }, + "WsAlertEventMetricsSubscribe": { + "name": "WsAlertEventMetricsSubscribe", + "title": "Event Metrics — Subscribe", + "summary": "Subscribe to `event_metrics` alerts", + "description": "Fired when an event's volume or transaction metrics cross a configured threshold. Use `timeframes` to restrict to specific windows (valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`).\n\n**Credits cost:** 1 per delivered alert.\n\n**Applicable filters:** `event_slugs`, `min_volume_usd`, `max_volume_usd`, `min_fees`, `min_txns`, `min_unique_traders`, `timeframes`, `exclude_shortterm_markets`", + "tags": [ + { + "name": "event" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertEventMetricsSubscribeMessage" + } + }, + "WsAlertEventMetricsUnsubscribe": { + "name": "WsAlertEventMetricsUnsubscribe", + "title": "Event Metrics — Unsubscribe", + "summary": "Unsubscribe from `event_metrics` alerts", + "description": "Unsubscribe from `event_metrics` alerts. The filter fields must match the original subscription exactly.", + "tags": [ + { + "name": "event" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertEventMetricsUnsubscribeMessage" + } + }, + "WsAlertEventMetricsEvent": { + "name": "WsAlertEventMetricsEvent", + "title": "Event Metrics — Event", + "summary": "`event_metrics` alert pushed from server", + "description": "Fired when an event's volume or transaction metrics cross a configured threshold. Use `timeframes` to restrict to specific windows (valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`).\n\n**Credits cost:** 1 per delivered alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "tags": [ + { + "name": "event" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertEventMetricsEvent" + } + }, + "WsAlertPositionMetricsSubscribe": { + "name": "WsAlertPositionMetricsSubscribe", + "title": "Position Metrics — Subscribe", + "summary": "Subscribe to `position_metrics` alerts", + "description": "Fired when a position's volume or transaction metrics cross a configured threshold. Use `timeframes` to restrict to specific windows (valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`).\n\n**Credits cost:** 1 per delivered alert.\n\n**Applicable filters:** `position_ids`, `condition_ids`, `outcomes`, `min_volume_usd`, `max_volume_usd`, `min_buy_usd`, `min_sell_volume_usd`, `min_fees`, `min_txns`, `min_price_change_pct`, `min_probability_change_pct`, `timeframes`", + "tags": [ + { + "name": "position" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertPositionMetricsSubscribeMessage" + } + }, + "WsAlertPositionMetricsUnsubscribe": { + "name": "WsAlertPositionMetricsUnsubscribe", + "title": "Position Metrics — Unsubscribe", + "summary": "Unsubscribe from `position_metrics` alerts", + "description": "Unsubscribe from `position_metrics` alerts. The filter fields must match the original subscription exactly.", + "tags": [ + { + "name": "position" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertPositionMetricsUnsubscribeMessage" + } + }, + "WsAlertPositionMetricsEvent": { + "name": "WsAlertPositionMetricsEvent", + "title": "Position Metrics — Event", + "summary": "`position_metrics` alert pushed from server", + "description": "Fired when a position's volume or transaction metrics cross a configured threshold. Use `timeframes` to restrict to specific windows (valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`).\n\n**Credits cost:** 1 per delivered alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "tags": [ + { + "name": "position" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertPositionMetricsEvent" + } + }, + "WsAlertMarketVolumeMilestoneSubscribe": { + "name": "WsAlertMarketVolumeMilestoneSubscribe", + "title": "Market Volume Milestone — Subscribe", + "summary": "Subscribe to `market_volume_milestone` alerts", + "description": "Fired when a market's trading volume crosses a milestone threshold in the specified timeframe. **`timeframes` is required** (e.g. `[\"1h\", \"24h\"]`) — valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`. Optional `milestone_amounts` restricts to specific USD thresholds (e.g. `[10000, 100000]`). Optional `condition_ids` restricts to specific markets.\n\n**Credits cost:** 2 per delivered alert.\n\n**Applicable filters:** `condition_ids`, `timeframes`, `milestone_amounts`", + "tags": [ + { + "name": "market" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertMarketVolumeMilestoneSubscribeMessage" + } + }, + "WsAlertMarketVolumeMilestoneUnsubscribe": { + "name": "WsAlertMarketVolumeMilestoneUnsubscribe", + "title": "Market Volume Milestone — Unsubscribe", + "summary": "Unsubscribe from `market_volume_milestone` alerts", + "description": "Unsubscribe from `market_volume_milestone` alerts. The filter fields must match the original subscription exactly.", + "tags": [ + { + "name": "market" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertMarketVolumeMilestoneUnsubscribeMessage" + } + }, + "WsAlertMarketVolumeMilestoneEvent": { + "name": "WsAlertMarketVolumeMilestoneEvent", + "title": "Market Volume Milestone — Event", + "summary": "`market_volume_milestone` alert pushed from server", + "description": "Fired when a market's trading volume crosses a milestone threshold in the specified timeframe. **`timeframes` is required** (e.g. `[\"1h\", \"24h\"]`) — valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`. Optional `milestone_amounts` restricts to specific USD thresholds (e.g. `[10000, 100000]`). Optional `condition_ids` restricts to specific markets.\n\n**Credits cost:** 2 per delivered alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "tags": [ + { + "name": "market" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertMarketVolumeMilestoneEvent" + } + }, + "WsAlertEventVolumeMilestoneSubscribe": { + "name": "WsAlertEventVolumeMilestoneSubscribe", + "title": "Event Volume Milestone — Subscribe", + "summary": "Subscribe to `event_volume_milestone` alerts", + "description": "Fired when an event's trading volume crosses a milestone threshold in the specified timeframe. **`timeframes` is required** (e.g. `[\"1h\", \"24h\"]`) — valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`. Optional `milestone_amounts` restricts to specific USD thresholds. Optional `event_slugs` restricts to specific events.\n\n**Credits cost:** 2 per delivered alert.\n\n**Applicable filters:** `event_slugs`, `timeframes`, `milestone_amounts`, `exclude_shortterm_markets`", + "tags": [ + { + "name": "event" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertEventVolumeMilestoneSubscribeMessage" + } + }, + "WsAlertEventVolumeMilestoneUnsubscribe": { + "name": "WsAlertEventVolumeMilestoneUnsubscribe", + "title": "Event Volume Milestone — Unsubscribe", + "summary": "Unsubscribe from `event_volume_milestone` alerts", + "description": "Unsubscribe from `event_volume_milestone` alerts. The filter fields must match the original subscription exactly.", + "tags": [ + { + "name": "event" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertEventVolumeMilestoneUnsubscribeMessage" + } + }, + "WsAlertEventVolumeMilestoneEvent": { + "name": "WsAlertEventVolumeMilestoneEvent", + "title": "Event Volume Milestone — Event", + "summary": "`event_volume_milestone` alert pushed from server", + "description": "Fired when an event's trading volume crosses a milestone threshold in the specified timeframe. **`timeframes` is required** (e.g. `[\"1h\", \"24h\"]`) — valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`. Optional `milestone_amounts` restricts to specific USD thresholds. Optional `event_slugs` restricts to specific events.\n\n**Credits cost:** 2 per delivered alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "tags": [ + { + "name": "event" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertEventVolumeMilestoneEvent" + } + }, + "WsAlertPositionVolumeMilestoneSubscribe": { + "name": "WsAlertPositionVolumeMilestoneSubscribe", + "title": "Position Volume Milestone — Subscribe", + "summary": "Subscribe to `position_volume_milestone` alerts", + "description": "Fired when a position's trading volume crosses a milestone threshold in the specified timeframe. **`timeframes` is required** (e.g. `[\"1h\", \"24h\"]`) — valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`. Optional `milestone_amounts` restricts to specific USD thresholds. Optional `position_ids` or `condition_ids` restrict to specific positions/markets.\n\n**Credits cost:** 2 per delivered alert.\n\n**Applicable filters:** `position_ids`, `condition_ids`, `outcomes`, `timeframes`, `milestone_amounts`", + "tags": [ + { + "name": "position" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertPositionVolumeMilestoneSubscribeMessage" + } + }, + "WsAlertPositionVolumeMilestoneUnsubscribe": { + "name": "WsAlertPositionVolumeMilestoneUnsubscribe", + "title": "Position Volume Milestone — Unsubscribe", + "summary": "Unsubscribe from `position_volume_milestone` alerts", + "description": "Unsubscribe from `position_volume_milestone` alerts. The filter fields must match the original subscription exactly.", + "tags": [ + { + "name": "position" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertPositionVolumeMilestoneUnsubscribeMessage" + } + }, + "WsAlertPositionVolumeMilestoneEvent": { + "name": "WsAlertPositionVolumeMilestoneEvent", + "title": "Position Volume Milestone — Event", + "summary": "`position_volume_milestone` alert pushed from server", + "description": "Fired when a position's trading volume crosses a milestone threshold in the specified timeframe. **`timeframes` is required** (e.g. `[\"1h\", \"24h\"]`) — valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`. Optional `milestone_amounts` restricts to specific USD thresholds. Optional `position_ids` or `condition_ids` restrict to specific positions/markets.\n\n**Credits cost:** 2 per delivered alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "tags": [ + { + "name": "position" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertPositionVolumeMilestoneEvent" + } + }, + "WsAlertProbabilitySpikeSubscribe": { + "name": "WsAlertProbabilitySpikeSubscribe", + "title": "Probability Spike — Subscribe", + "summary": "Subscribe to `probability_spike` alerts", + "description": "Fired when a position's probability moves significantly. Use `min_probability_change_pct` to set the minimum move (e.g. `10` for 10%). Use `window_secs` to observe moves within a specific time window (e.g. `60` for 60 seconds). Use `spike_direction` (`\"up\"` | `\"down\"` | `\"both\"`) — defaults to `\"up\"` when not provided. Filter by `position_ids` or `outcomes` to narrow scope.\n\n**Credits cost:** 2 per delivered alert.\n\n**Applicable filters:** `position_ids`, `condition_ids`, `event_slugs`, `outcomes`, `min_probability_change_pct`, `spike_direction`, `window_secs`, `exclude_shortterm_markets`", + "tags": [ + { + "name": "position" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertProbabilitySpikeSubscribeMessage" + } + }, + "WsAlertProbabilitySpikeUnsubscribe": { + "name": "WsAlertProbabilitySpikeUnsubscribe", + "title": "Probability Spike — Unsubscribe", + "summary": "Unsubscribe from `probability_spike` alerts", + "description": "Unsubscribe from `probability_spike` alerts. The filter fields must match the original subscription exactly.", + "tags": [ + { + "name": "position" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertProbabilitySpikeUnsubscribeMessage" + } + }, + "WsAlertProbabilitySpikeEvent": { + "name": "WsAlertProbabilitySpikeEvent", + "title": "Probability Spike — Event", + "summary": "`probability_spike` alert pushed from server", + "description": "Fired when a position's probability moves significantly. Use `min_probability_change_pct` to set the minimum move (e.g. `10` for 10%). Use `window_secs` to observe moves within a specific time window (e.g. `60` for 60 seconds). Use `spike_direction` (`\"up\"` | `\"down\"` | `\"both\"`) — defaults to `\"up\"` when not provided. Filter by `position_ids` or `outcomes` to narrow scope.\n\n**Credits cost:** 2 per delivered alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "tags": [ + { + "name": "position" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertProbabilitySpikeEvent" + } + }, + "WsAlertPriceSpikeSubscribe": { + "name": "WsAlertPriceSpikeSubscribe", + "title": "Price Spike — Subscribe", + "summary": "Subscribe to `price_spike` alerts", + "description": "Fired when a position's price moves significantly. Use `min_price_change_pct` to set the minimum move (e.g. `10` for 10%). Use `window_secs` to observe moves within a specific time window. Use `spike_direction` (`\"up\"` | `\"down\"` | `\"both\"`) — defaults to `\"up\"` when not provided. Filter by `position_ids` or `outcomes` to narrow scope.\n\n**Credits cost:** 2 per delivered alert.\n\n**Applicable filters:** `position_ids`, `condition_ids`, `event_slugs`, `outcomes`, `min_price_change_pct`, `spike_direction`, `window_secs`, `exclude_shortterm_markets`", + "tags": [ + { + "name": "position" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertPriceSpikeSubscribeMessage" + } + }, + "WsAlertPriceSpikeUnsubscribe": { + "name": "WsAlertPriceSpikeUnsubscribe", + "title": "Price Spike — Unsubscribe", + "summary": "Unsubscribe from `price_spike` alerts", + "description": "Unsubscribe from `price_spike` alerts. The filter fields must match the original subscription exactly.", + "tags": [ + { + "name": "position" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertPriceSpikeUnsubscribeMessage" + } + }, + "WsAlertPriceSpikeEvent": { + "name": "WsAlertPriceSpikeEvent", + "title": "Price Spike — Event", + "summary": "`price_spike` alert pushed from server", + "description": "Fired when a position's price moves significantly. Use `min_price_change_pct` to set the minimum move (e.g. `10` for 10%). Use `window_secs` to observe moves within a specific time window. Use `spike_direction` (`\"up\"` | `\"down\"` | `\"both\"`) — defaults to `\"up\"` when not provided. Filter by `position_ids` or `outcomes` to narrow scope.\n\n**Credits cost:** 2 per delivered alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "tags": [ + { + "name": "position" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertPriceSpikeEvent" + } + }, + "WsAlertMarketVolumeSpikeSubscribe": { + "name": "WsAlertMarketVolumeSpikeSubscribe", + "title": "Market Volume Spike — Subscribe", + "summary": "Subscribe to `market_volume_spike` alerts", + "description": "Fired when a market's trading volume grows by a multiple of `spike_ratio` within a timeframe. Requires `spike_ratio` (> 1.0, e.g. `2.0` fires when volume doubles). Optional `window_secs` sets the observation window in seconds (max 600). Optional `timeframes` — valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `1d`, `24h`, `7d`, `30d`. Optional `condition_ids` restricts to specific markets.\n\n**Credits cost:** 2 per delivered alert.\n\n**Applicable filters:** `spike_ratio`, `window_secs`, `condition_ids`, `timeframes`", + "tags": [ + { + "name": "market" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertMarketVolumeSpikeSubscribeMessage" + } + }, + "WsAlertMarketVolumeSpikeUnsubscribe": { + "name": "WsAlertMarketVolumeSpikeUnsubscribe", + "title": "Market Volume Spike — Unsubscribe", + "summary": "Unsubscribe from `market_volume_spike` alerts", + "description": "Unsubscribe from `market_volume_spike` alerts. The filter fields must match the original subscription exactly.", + "tags": [ + { + "name": "market" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertMarketVolumeSpikeUnsubscribeMessage" + } + }, + "WsAlertMarketVolumeSpikeEvent": { + "name": "WsAlertMarketVolumeSpikeEvent", + "title": "Market Volume Spike — Event", + "summary": "`market_volume_spike` alert pushed from server", + "description": "Fired when a market's trading volume grows by a multiple of `spike_ratio` within a timeframe. Requires `spike_ratio` (> 1.0, e.g. `2.0` fires when volume doubles). Optional `window_secs` sets the observation window in seconds (max 600). Optional `timeframes` — valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `1d`, `24h`, `7d`, `30d`. Optional `condition_ids` restricts to specific markets.\n\n**Credits cost:** 2 per delivered alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "tags": [ + { + "name": "market" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertMarketVolumeSpikeEvent" + } + }, + "WsAlertEventVolumeSpikeSubscribe": { + "name": "WsAlertEventVolumeSpikeSubscribe", + "title": "Event Volume Spike — Subscribe", + "summary": "Subscribe to `event_volume_spike` alerts", + "description": "Fired when an event's aggregated trading volume grows by a multiple of `spike_ratio` within a timeframe. Requires `spike_ratio` (> 1.0, e.g. `2.0` fires when volume doubles). Optional `window_secs` sets the observation window in seconds (max 600). Optional `timeframes` and `event_slugs` to narrow scope.\n\n**Credits cost:** 2 per delivered alert.\n\n**Applicable filters:** `spike_ratio`, `window_secs`, `event_slugs`, `timeframes`, `exclude_shortterm_markets`", + "tags": [ + { + "name": "event" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertEventVolumeSpikeSubscribeMessage" + } + }, + "WsAlertEventVolumeSpikeUnsubscribe": { + "name": "WsAlertEventVolumeSpikeUnsubscribe", + "title": "Event Volume Spike — Unsubscribe", + "summary": "Unsubscribe from `event_volume_spike` alerts", + "description": "Unsubscribe from `event_volume_spike` alerts. The filter fields must match the original subscription exactly.", + "tags": [ + { + "name": "event" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertEventVolumeSpikeUnsubscribeMessage" + } + }, + "WsAlertEventVolumeSpikeEvent": { + "name": "WsAlertEventVolumeSpikeEvent", + "title": "Event Volume Spike — Event", + "summary": "`event_volume_spike` alert pushed from server", + "description": "Fired when an event's aggregated trading volume grows by a multiple of `spike_ratio` within a timeframe. Requires `spike_ratio` (> 1.0, e.g. `2.0` fires when volume doubles). Optional `window_secs` sets the observation window in seconds (max 600). Optional `timeframes` and `event_slugs` to narrow scope.\n\n**Credits cost:** 2 per delivered alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "tags": [ + { + "name": "event" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertEventVolumeSpikeEvent" + } + }, + "WsAlertPositionVolumeSpikeSubscribe": { + "name": "WsAlertPositionVolumeSpikeSubscribe", + "title": "Position Volume Spike — Subscribe", + "summary": "Subscribe to `position_volume_spike` alerts", + "description": "Fired when a position's trading volume grows by a multiple of `spike_ratio` within a timeframe. Requires `spike_ratio` (> 1.0, e.g. `2.0` fires when volume doubles). Optional `window_secs` sets the observation window in seconds (max 600). Optional `position_ids`, `condition_ids`, `outcomes`, and `timeframes` to narrow scope.\n\n**Credits cost:** 2 per delivered alert.\n\n**Applicable filters:** `spike_ratio`, `window_secs`, `position_ids`, `condition_ids`, `outcomes`, `timeframes`", + "tags": [ + { + "name": "position" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertPositionVolumeSpikeSubscribeMessage" + } + }, + "WsAlertPositionVolumeSpikeUnsubscribe": { + "name": "WsAlertPositionVolumeSpikeUnsubscribe", + "title": "Position Volume Spike — Unsubscribe", + "summary": "Unsubscribe from `position_volume_spike` alerts", + "description": "Unsubscribe from `position_volume_spike` alerts. The filter fields must match the original subscription exactly.", + "tags": [ + { + "name": "position" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertPositionVolumeSpikeUnsubscribeMessage" + } + }, + "WsAlertPositionVolumeSpikeEvent": { + "name": "WsAlertPositionVolumeSpikeEvent", + "title": "Position Volume Spike — Event", + "summary": "`position_volume_spike` alert pushed from server", + "description": "Fired when a position's trading volume grows by a multiple of `spike_ratio` within a timeframe. Requires `spike_ratio` (> 1.0, e.g. `2.0` fires when volume doubles). Optional `window_secs` sets the observation window in seconds (max 600). Optional `position_ids`, `condition_ids`, `outcomes`, and `timeframes` to narrow scope.\n\n**Credits cost:** 2 per delivered alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "tags": [ + { + "name": "position" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertPositionVolumeSpikeEvent" + } + }, + "WsAlertCloseToBondSubscribe": { + "name": "WsAlertCloseToBondSubscribe", + "title": "Close To Bond — Subscribe", + "summary": "Subscribe to `close_to_bond` alerts", + "description": "Fired when a trade occurs at a near-certain-outcome price. **At least one of `min_probability` or `max_probability` is required.** Use `min_probability` (e.g. `0.95`) to trigger when YES is near-certain; use `max_probability` (e.g. `0.05`) for NO near-certain. Optional filters: `position_outcome_indices` — restrict by outcome index (`0` = Yes/Up, `1` = No); `condition_ids` — restrict to specific markets; `position_ids` — restrict to specific outcome tokens; `outcomes` — restrict by outcome name (e.g. `\"Yes\"`, `\"No\"`); `event_slugs` — restrict to specific events.\n\n**Credits cost:** 2 per delivered alert.\n\n**Applicable filters:** `min_probability`, `max_probability`, `condition_ids`, `position_ids`, `outcomes`, `position_outcome_indices`, `event_slugs`, `exclude_shortterm_markets`", + "tags": [ + { + "name": "market" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertCloseToBondSubscribeMessage" + } + }, + "WsAlertCloseToBondUnsubscribe": { + "name": "WsAlertCloseToBondUnsubscribe", + "title": "Close To Bond — Unsubscribe", + "summary": "Unsubscribe from `close_to_bond` alerts", + "description": "Unsubscribe from `close_to_bond` alerts. The filter fields must match the original subscription exactly.", + "tags": [ + { + "name": "market" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertCloseToBondUnsubscribeMessage" + } + }, + "WsAlertCloseToBondEvent": { + "name": "WsAlertCloseToBondEvent", + "title": "Close To Bond — Event", + "summary": "`close_to_bond` alert pushed from server", + "description": "Fired when a trade occurs at a near-certain-outcome price. **At least one of `min_probability` or `max_probability` is required.** Use `min_probability` (e.g. `0.95`) to trigger when YES is near-certain; use `max_probability` (e.g. `0.05`) for NO near-certain. Optional filters: `position_outcome_indices` — restrict by outcome index (`0` = Yes/Up, `1` = No); `condition_ids` — restrict to specific markets; `position_ids` — restrict to specific outcome tokens; `outcomes` — restrict by outcome name (e.g. `\"Yes\"`, `\"No\"`); `event_slugs` — restrict to specific events.\n\n**Credits cost:** 2 per delivered alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "tags": [ + { + "name": "market" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertCloseToBondEvent" + } + }, + "WsAlertMarketCreatedSubscribe": { + "name": "WsAlertMarketCreatedSubscribe", + "title": "Market Created — Subscribe", + "summary": "Subscribe to `market_created` alerts", + "description": "Fired when a new prediction market is created on Polymarket. Filterable by `tags` and `event_slugs`.\n\n**Credits cost:** 1 per delivered alert.\n\n**Applicable filters:** `event_slugs`, `tags`, `exclude_shortterm_markets`", + "tags": [ + { + "name": "market" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertMarketCreatedSubscribeMessage" + } + }, + "WsAlertMarketCreatedUnsubscribe": { + "name": "WsAlertMarketCreatedUnsubscribe", + "title": "Market Created — Unsubscribe", + "summary": "Unsubscribe from `market_created` alerts", + "description": "Unsubscribe from `market_created` alerts. The filter fields must match the original subscription exactly.", + "tags": [ + { + "name": "market" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertMarketCreatedUnsubscribeMessage" + } + }, + "WsAlertMarketCreatedEvent": { + "name": "WsAlertMarketCreatedEvent", + "title": "Market Created — Event", + "summary": "`market_created` alert pushed from server", + "description": "Fired when a new prediction market is created on Polymarket. Filterable by `tags` and `event_slugs`.\n\n**Credits cost:** 1 per delivered alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "tags": [ + { + "name": "market" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertMarketCreatedEvent" + } + }, + "WsAlertAssetPriceTickSubscribe": { + "name": "WsAlertAssetPriceTickSubscribe", + "title": "Asset Price Tick — Subscribe", + "summary": "Subscribe to `asset_price_tick` alerts", + "description": "Fired when the price of a tracked crypto asset updates (BTC, ETH, SOL, XRP, DOGE, BNB, HYPE). Use `asset_symbols` to restrict to specific assets (empty = all).\n\n**Credits cost:** 1 per delivered alert.\n\n**Applicable filters:** `asset_symbols`", + "tags": [ + { + "name": "assets" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertAssetPriceTickSubscribeMessage" + } + }, + "WsAlertAssetPriceTickUnsubscribe": { + "name": "WsAlertAssetPriceTickUnsubscribe", + "title": "Asset Price Tick — Unsubscribe", + "summary": "Unsubscribe from `asset_price_tick` alerts", + "description": "Unsubscribe from `asset_price_tick` alerts. The filter fields must match the original subscription exactly.", + "tags": [ + { + "name": "assets" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertAssetPriceTickUnsubscribeMessage" + } + }, + "WsAlertAssetPriceTickEvent": { + "name": "WsAlertAssetPriceTickEvent", + "title": "Asset Price Tick — Event", + "summary": "`asset_price_tick` alert pushed from server", + "description": "Fired when the price of a tracked crypto asset updates (BTC, ETH, SOL, XRP, DOGE, BNB, HYPE). Use `asset_symbols` to restrict to specific assets (empty = all).\n\n**Credits cost:** 1 per delivered alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "tags": [ + { + "name": "assets" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertAssetPriceTickEvent" + } + }, + "WsAlertAssetPriceWindowUpdateSubscribe": { + "name": "WsAlertAssetPriceWindowUpdateSubscribe", + "title": "Asset Price Window Update — Subscribe", + "summary": "Subscribe to `asset_price_window_update` alerts", + "description": "Fired at the start and end of each price candle for tracked crypto assets (BTC, ETH, SOL, XRP, DOGE, BNB, HYPE). Payload includes `update_type` (`\"open\"` or `\"close\"`) indicating whether the candle is opening or closing. Use `asset_symbols` to restrict to specific assets. Use `timeframes` to restrict to specific candle sizes — valid values: `\"5m\"`, `\"15m\"`, `\"1h\"`, `\"4h\"`, `\"1d\"`, `\"24h\"`.\n\n**Credits cost:** 1 per delivered alert.\n\n**Applicable filters:** `asset_symbols`, `timeframes`", + "tags": [ + { + "name": "assets" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertAssetPriceWindowUpdateSubscribeMessage" + } + }, + "WsAlertAssetPriceWindowUpdateUnsubscribe": { + "name": "WsAlertAssetPriceWindowUpdateUnsubscribe", + "title": "Asset Price Window Update — Unsubscribe", + "summary": "Unsubscribe from `asset_price_window_update` alerts", + "description": "Unsubscribe from `asset_price_window_update` alerts. The filter fields must match the original subscription exactly.", + "tags": [ + { + "name": "assets" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertAssetPriceWindowUpdateUnsubscribeMessage" + } + }, + "WsAlertAssetPriceWindowUpdateEvent": { + "name": "WsAlertAssetPriceWindowUpdateEvent", + "title": "Asset Price Window Update — Event", + "summary": "`asset_price_window_update` alert pushed from server", + "description": "Fired at the start and end of each price candle for tracked crypto assets (BTC, ETH, SOL, XRP, DOGE, BNB, HYPE). Payload includes `update_type` (`\"open\"` or `\"close\"`) indicating whether the candle is opening or closing. Use `asset_symbols` to restrict to specific assets. Use `timeframes` to restrict to specific candle sizes — valid values: `\"5m\"`, `\"15m\"`, `\"1h\"`, `\"4h\"`, `\"1d\"`, `\"24h\"`.\n\n**Credits cost:** 1 per delivered alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "tags": [ + { + "name": "assets" + } + ], + "payload": { + "$ref": "#/components/schemas/WsAlertAssetPriceWindowUpdateEvent" + } + }, + "WsAlertSubscribed": { + "summary": "Alert subscription acknowledgement", + "payload": { + "$ref": "#/components/schemas/WsAlertSubscribedResponse" + } + }, + "WsAlertUnsubscribed": { + "summary": "Alert unsubscription acknowledgement", + "payload": { + "$ref": "#/components/schemas/WsAlertUnsubscribedResponse" + } + }, + "WsAlertError": { + "summary": "Alerts WebSocket error response", + "payload": { + "$ref": "#/components/schemas/WsAlertErrorResponse" + } + } + }, + "schemas": { + "WebhookDeliveryEnvelope": { + "type": "object", + "description": "Outer envelope for every webhook HTTP POST delivery. The `data` field contains the event-specific payload. Delivery headers sent with every POST: `X-Webhook-ID` (subscription UUID), `X-Delivery-ID` (this attempt's UUID), `X-Event-Type` (event name string, e.g. `trader_first_trade`), `X-Attempt` (attempt number, 1-indexed). When the webhook has a secret configured, `X-Webhook-Signature: sha256=` is also included — compute HMAC-SHA256 over the raw request body using your secret to verify.", + "required": [ + "id", + "event", + "data", + "timestamp", + "webhook_id", + "attempt" + ], + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "UUID of this specific delivery attempt (matches X-Delivery-ID header)" + }, + "event": { + "type": "string", + "description": "Event name (e.g. `trader_first_trade`). On test deliveries the suffix `_test` is appended." + }, + "data": { + "type": "object", + "description": "Event-specific payload — schema varies by event type; see the individual callback definitions" + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix timestamp in milliseconds when this delivery was created" + }, + "webhook_id": { + "type": "string", + "format": "uuid", + "description": "UUID of the webhook subscription that fired (matches X-Webhook-ID header)" + }, + "attempt": { + "type": "integer", + "minimum": 1, + "description": "Delivery attempt number. 1 = first attempt; increments on each retry." + } + } + }, + "FirstTradePayload": { + "type": "object", + "description": "Payload delivered when a tracked trader executes their first-ever trade on Polymarket", + "required": [ + "trader", + "taker", + "position_id", + "trade_id", + "hash", + "block", + "confirmed_at", + "amount_usd", + "shares_amount", + "fee", + "side", + "price", + "exchange", + "trade_type" + ], + "properties": { + "trader": { + "type": "string", + "description": "Limit-order maker wallet address (lowercase)" + }, + "taker": { + "type": "string", + "description": "Order filler wallet address (lowercase)" + }, + "position_id": { + "type": "string", + "description": "ERC-1155 outcome token ID" + }, + "condition_id": { + "type": [ + "string", + "null" + ], + "description": "Parent market condition ID (0x-prefixed hex)" + }, + "outcome": { + "type": [ + "string", + "null" + ], + "description": "Outcome name (e.g. \"Yes\", \"No\")" + }, + "outcome_index": { + "type": [ + "integer", + "null" + ], + "description": "Outcome index: 0 = Yes/Up, 1 = No" + }, + "question": { + "type": [ + "string", + "null" + ], + "description": "Market question text" + }, + "market_slug": { + "type": [ + "string", + "null" + ], + "description": "Market slug" + }, + "event_slug": { + "type": [ + "string", + "null" + ], + "description": "Parent event slug" + }, + "trade_id": { + "type": "string", + "description": "Unique trade identifier" + }, + "hash": { + "type": "string", + "description": "Transaction hash" + }, + "block": { + "type": "integer", + "format": "int64", + "description": "Block number" + }, + "confirmed_at": { + "type": "integer", + "format": "int64", + "description": "Block confirmation timestamp (Unix seconds)" + }, + "amount_usd": { + "type": "number", + "description": "USD size of the trade (6 decimal places)" + }, + "shares_amount": { + "type": "number", + "description": "Outcome shares traded (6 decimal places)" + }, + "fee": { + "type": "number", + "description": "Fee paid in USD (6 decimal places)" + }, + "side": { + "type": "string", + "enum": [ + "Buy", + "Sell" + ], + "description": "Trade direction" + }, + "price": { + "type": "number", + "minimum": 0.0, + "maximum": 1.0, + "description": "Outcome token price (0.0–1.0)" + }, + "exchange": { + "type": "string", + "description": "Exchange identifier" + }, + "trade_type": { + "type": "string", + "description": "Trade type identifier" + } + } + }, + "NewMarketPayload": { + "type": "object", + "description": "Payload delivered when a trader places their first trade in a specific market (fires once per trader+market pair)", + "required": [ + "trader", + "taker", + "position_id", + "trade_id", + "hash", + "block", + "confirmed_at", + "amount_usd", + "shares_amount", + "fee", + "side", + "price", + "exchange", + "trade_type" + ], + "properties": { + "trader": { + "type": "string", + "description": "Limit-order maker wallet address (lowercase)" + }, + "taker": { + "type": "string", + "description": "Order filler wallet address (lowercase)" + }, + "position_id": { + "type": "string", + "description": "ERC-1155 outcome token ID" + }, + "condition_id": { + "type": [ + "string", + "null" + ], + "description": "Parent market condition ID" + }, + "outcome": { + "type": [ + "string", + "null" + ], + "description": "Outcome name (e.g. \"Yes\", \"No\")" + }, + "outcome_index": { + "type": [ + "integer", + "null" + ], + "description": "Outcome index: 0 = Yes/Up, 1 = No" + }, + "question": { + "type": [ + "string", + "null" + ], + "description": "Market question text" + }, + "market_slug": { + "type": [ + "string", + "null" + ], + "description": "Market slug" + }, + "event_slug": { + "type": [ + "string", + "null" + ], + "description": "Parent event slug" + }, + "trade_id": { + "type": "string", + "description": "Unique trade identifier" + }, + "hash": { + "type": "string", + "description": "Transaction hash" + }, + "block": { + "type": "integer", + "format": "int64", + "description": "Block number" + }, + "confirmed_at": { + "type": "integer", + "format": "int64", + "description": "Block confirmation timestamp (Unix seconds)" + }, + "amount_usd": { + "type": "number", + "description": "USD size of the trade (6 decimal places)" + }, + "shares_amount": { + "type": "number", + "description": "Outcome shares traded (6 decimal places)" + }, + "fee": { + "type": "number", + "description": "Fee paid in USD (6 decimal places)" + }, + "side": { + "type": "string", + "enum": [ + "Buy", + "Sell" + ], + "description": "Trade direction" + }, + "price": { + "type": "number", + "minimum": 0.0, + "maximum": 1.0, + "description": "Outcome token price (0.0–1.0)" + }, + "probability": { + "type": [ + "number", + "null" + ], + "minimum": 0.0, + "maximum": 1.0, + "description": "Implied probability (0.0–1.0); null when outcome is unknown" + }, + "exchange": { + "type": "string", + "description": "Exchange identifier" + }, + "trade_type": { + "type": "string", + "description": "Trade type identifier" + } + } + }, + "WhaleTradePayload": { + "type": "object", + "description": "Payload delivered when a trade exceeds the configured size and probability thresholds", + "required": [ + "trader", + "taker", + "position_id", + "trade_id", + "hash", + "block", + "confirmed_at", + "amount_usd", + "shares_amount", + "fee", + "side", + "price", + "exchange", + "trade_type" + ], + "properties": { + "trader": { + "type": "string", + "description": "Limit-order maker wallet address (lowercase)" + }, + "taker": { + "type": "string", + "description": "Order filler wallet address (lowercase)" + }, + "position_id": { + "type": "string", + "description": "ERC-1155 outcome token ID" + }, + "condition_id": { + "type": [ + "string", + "null" + ], + "description": "Parent market condition ID" + }, + "outcome": { + "type": [ + "string", + "null" + ], + "description": "Outcome name (e.g. \"Yes\", \"No\")" + }, + "outcome_index": { + "type": [ + "integer", + "null" + ], + "description": "Outcome index: 0 = Yes/Up, 1 = No" + }, + "question": { + "type": [ + "string", + "null" + ], + "description": "Market question text" + }, + "market_slug": { + "type": [ + "string", + "null" + ], + "description": "Market slug" + }, + "event_slug": { + "type": [ + "string", + "null" + ], + "description": "Parent event slug" + }, + "trade_id": { + "type": "string", + "description": "Unique trade identifier" + }, + "hash": { + "type": "string", + "description": "Transaction hash" + }, + "block": { + "type": "integer", + "format": "int64", + "description": "Block number" + }, + "confirmed_at": { + "type": "integer", + "format": "int64", + "description": "Block confirmation timestamp (Unix seconds)" + }, + "amount_usd": { + "type": "number", + "description": "USD size of the trade (6 decimal places)" + }, + "shares_amount": { + "type": "number", + "description": "Outcome shares traded (6 decimal places)" + }, + "fee": { + "type": "number", + "description": "Fee paid in USD (6 decimal places)" + }, + "side": { + "type": "string", + "enum": [ + "Buy", + "Sell" + ], + "description": "Trade direction" + }, + "price": { + "type": "number", + "minimum": 0.0, + "maximum": 1.0, + "description": "Outcome token price (0.0–1.0)" + }, + "probability": { + "type": [ + "number", + "null" + ], + "minimum": 0.0, + "maximum": 1.0, + "description": "Implied probability (0.0–1.0); null when outcome is unknown" + }, + "exchange": { + "type": "string", + "description": "Exchange identifier" + }, + "trade_type": { + "type": "string", + "description": "Trade type identifier" + } + } + }, + "NewTradePayload": { + "type": "object", + "description": "Payload delivered on every order-filled trade", + "required": [ + "trader", + "taker", + "position_id", + "trade_id", + "hash", + "block", + "confirmed_at", + "amount_usd", + "shares_amount", + "fee", + "side", + "price", + "exchange", + "trade_type" + ], + "properties": { + "trader": { + "type": "string", + "description": "Limit-order maker wallet address (lowercase)" + }, + "taker": { + "type": "string", + "description": "Order filler wallet address (lowercase)" + }, + "position_id": { + "type": "string", + "description": "ERC-1155 outcome token ID" + }, + "condition_id": { + "type": [ + "string", + "null" + ], + "description": "Parent market condition ID" + }, + "outcome": { + "type": [ + "string", + "null" + ], + "description": "Outcome name (e.g. \"Yes\", \"No\")" + }, + "outcome_index": { + "type": [ + "integer", + "null" + ], + "description": "Outcome index: 0 = Yes/Up, 1 = No" + }, + "question": { + "type": [ + "string", + "null" + ], + "description": "Market question text" + }, + "market_slug": { + "type": [ + "string", + "null" + ], + "description": "Market slug" + }, + "event_slug": { + "type": [ + "string", + "null" + ], + "description": "Parent event slug" + }, + "trade_id": { + "type": "string", + "description": "Unique trade identifier" + }, + "hash": { + "type": "string", + "description": "Transaction hash" + }, + "block": { + "type": "integer", + "format": "int64", + "description": "Block number" + }, + "confirmed_at": { + "type": "integer", + "format": "int64", + "description": "Block confirmation timestamp (Unix seconds)" + }, + "amount_usd": { + "type": "number", + "description": "USD size of the trade (6 decimal places)" + }, + "shares_amount": { + "type": "number", + "description": "Outcome shares traded (6 decimal places)" + }, + "fee": { + "type": "number", + "description": "Fee paid in USD (6 decimal places)" + }, + "side": { + "type": "string", + "enum": [ + "Buy", + "Sell" + ], + "description": "Trade direction" + }, + "price": { + "type": "number", + "minimum": 0.0, + "maximum": 1.0, + "description": "Outcome token price (0.0–1.0)" + }, + "probability": { + "type": [ + "number", + "null" + ], + "minimum": 0.0, + "maximum": 1.0, + "description": "Implied probability (0.0–1.0); null when outcome is unknown" + }, + "exchange": { + "type": "string", + "description": "Exchange identifier" + }, + "trade_type": { + "type": "string", + "description": "Trade type identifier" + } + } + }, + "GlobalPnlPayload": { + "type": "object", + "description": "Payload delivered when a trader's global PnL (across all markets) crosses a configured threshold", + "required": [ + "timeframe" + ], + "properties": { + "trader": { + "type": [ + "string", + "null" + ], + "description": "Trader wallet address (lowercase)" + }, + "timeframe": { + "type": "string", + "enum": [ + "1d", + "7d", + "30d", + "lifetime" + ], + "description": "PnL aggregation window" + }, + "realized_pnl_usd": { + "type": [ + "number", + "null" + ], + "description": "Realized PnL in USD (positive = profit, negative = loss)" + }, + "events_traded": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Number of distinct events traded" + }, + "markets_traded": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Number of distinct markets traded" + }, + "total_buys": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Total buy transactions" + }, + "total_sells": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Total sell transactions" + }, + "total_redemptions": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Total redemption transactions" + }, + "total_merges": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Total merge transactions" + }, + "total_volume_usd": { + "type": [ + "number", + "null" + ], + "description": "Total USD volume (buys + sells + redemptions + merges)" + }, + "buy_volume_usd": { + "type": [ + "number", + "null" + ], + "description": "Total buy volume in USD" + }, + "sell_volume_usd": { + "type": [ + "number", + "null" + ], + "description": "Total sell volume in USD" + }, + "redemption_volume_usd": { + "type": [ + "number", + "null" + ], + "description": "Total redemption volume in USD" + }, + "merge_volume_usd": { + "type": [ + "number", + "null" + ], + "description": "Total merge volume in USD" + }, + "markets_won": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Number of markets where trader realised a profit" + }, + "markets_lost": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Number of markets where trader realised a loss" + }, + "market_win_rate_pct": { + "type": [ + "number", + "null" + ], + "description": "Market win rate as a percentage (0.0–100.0)" + }, + "avg_pnl_per_market": { + "type": [ + "number", + "null" + ], + "description": "Average PnL per market in USD" + }, + "avg_pnl_per_trade": { + "type": [ + "number", + "null" + ], + "description": "Average PnL per trade in USD" + }, + "avg_hold_time_seconds": { + "type": [ + "number", + "null" + ], + "description": "Average hold time across all positions (seconds)" + }, + "total_fees": { + "type": [ + "number", + "null" + ], + "description": "Total fees paid in USD" + }, + "best_trade_pnl_usd": { + "type": [ + "number", + "null" + ], + "description": "Best single-trade PnL in USD" + }, + "best_trade_condition_id": { + "type": [ + "string", + "null" + ], + "description": "Condition ID of the best trade" + }, + "first_trade_at": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Timestamp of the first trade (Unix seconds)" + }, + "last_trade_at": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Timestamp of the most recent trade (Unix seconds)" + } + } + }, + "MarketPnlPayload": { + "type": "object", + "description": "Payload delivered when a trader's per-market PnL crosses a configured threshold", + "required": [ + "timeframe" + ], + "properties": { + "trader": { + "type": [ + "string", + "null" + ], + "description": "Trader wallet address (lowercase)" + }, + "condition_id": { + "type": [ + "string", + "null" + ], + "description": "Market condition ID" + }, + "event_slug": { + "type": [ + "string", + "null" + ], + "description": "Parent event slug" + }, + "timeframe": { + "type": "string", + "enum": [ + "1d", + "7d", + "30d", + "lifetime" + ], + "description": "PnL aggregation window" + }, + "outcomes_traded": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Number of distinct outcomes traded in this market" + }, + "total_buys": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "total_sells": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "total_redemptions": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "total_merges": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "buy_usd": { + "type": [ + "number", + "null" + ], + "description": "Total buy volume in USD" + }, + "sell_usd": { + "type": [ + "number", + "null" + ], + "description": "Total sell volume in USD" + }, + "redemption_usd": { + "type": [ + "number", + "null" + ], + "description": "Total redemption volume in USD" + }, + "merge_usd": { + "type": [ + "number", + "null" + ], + "description": "Total merge volume in USD" + }, + "realized_pnl_usd": { + "type": [ + "number", + "null" + ], + "description": "Realized PnL in USD for this market" + }, + "winning_outcomes": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Number of outcomes with positive PnL" + }, + "total_fees": { + "type": [ + "number", + "null" + ], + "description": "Total fees paid in USD for this market" + }, + "first_trade_at": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Timestamp of first trade in market (Unix seconds)" + }, + "last_trade_at": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Timestamp of most recent trade in market (Unix seconds)" + } + } + }, + "EventPnlPayload": { + "type": "object", + "description": "Payload delivered when a trader's per-event PnL crosses a configured threshold", + "required": [ + "timeframe" + ], + "properties": { + "trader": { + "type": [ + "string", + "null" + ], + "description": "Trader wallet address (lowercase)" + }, + "event_slug": { + "type": [ + "string", + "null" + ], + "description": "Event slug" + }, + "timeframe": { + "type": "string", + "enum": [ + "1d", + "7d", + "30d", + "lifetime" + ], + "description": "PnL aggregation window" + }, + "markets_traded": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Number of distinct markets traded in this event" + }, + "outcomes_traded": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "total_buys": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "total_sells": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "total_redemptions": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "total_merges": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "total_volume_usd": { + "type": [ + "number", + "null" + ], + "description": "Total volume in USD" + }, + "buy_usd": { + "type": [ + "number", + "null" + ] + }, + "sell_usd": { + "type": [ + "number", + "null" + ] + }, + "redemption_usd": { + "type": [ + "number", + "null" + ] + }, + "merge_usd": { + "type": [ + "number", + "null" + ] + }, + "realized_pnl_usd": { + "type": [ + "number", + "null" + ], + "description": "Realized PnL in USD for this event" + }, + "winning_markets": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "losing_markets": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "total_fees": { + "type": [ + "number", + "null" + ] + }, + "first_trade_at": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Unix seconds" + }, + "last_trade_at": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Unix seconds" + } + } + }, + "ConditionMetricsPayload": { + "type": "object", + "description": "Payload delivered when a market's volume or transaction metrics cross a configured threshold", + "properties": { + "condition_id": { + "type": [ + "string", + "null" + ], + "description": "Market condition ID" + }, + "timeframe": { + "type": [ + "string", + "null" + ], + "description": "Aggregation window (e.g. \"1h\", \"24h\")" + }, + "volume_usd": { + "type": [ + "number", + "null" + ], + "description": "Total trading volume in USD for this timeframe" + }, + "fees": { + "type": [ + "number", + "null" + ], + "description": "Total fees collected in USD" + }, + "txns": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Total number of transactions" + }, + "unique_traders": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Number of unique traders" + } + } + }, + "EventMetricsPayload": { + "type": "object", + "description": "Payload delivered when an event's aggregated volume or transaction metrics cross a configured threshold", + "properties": { + "event_slug": { + "type": [ + "string", + "null" + ], + "description": "Event slug" + }, + "timeframe": { + "type": [ + "string", + "null" + ], + "description": "Aggregation window (e.g. \"1h\", \"24h\")" + }, + "volume_usd": { + "type": [ + "number", + "null" + ], + "description": "Total aggregated volume across all markets in the event (USD)" + }, + "fees": { + "type": [ + "number", + "null" + ], + "description": "Total fees collected in USD" + }, + "txns": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Total number of transactions" + }, + "unique_traders": { + "type": [ + "integer", + "null" + ], + "format": "int64", + "description": "Number of unique traders" + } + } + }, + "PositionMetricsPayload": { + "type": "object", + "description": "Payload delivered when a position's volume or transaction metrics cross a configured threshold", + "properties": { + "position_id": { + "type": [ + "string", + "null" + ], + "description": "ERC-1155 outcome token ID" + }, + "outcome": { + "type": [ + "string", + "null" + ], + "description": "Outcome name (e.g. \"Yes\", \"No\")" + }, + "outcome_index": { + "type": [ + "integer", + "null" + ], + "format": "int16", + "description": "Outcome index" + }, + "timeframe": { + "type": [ + "string", + "null" + ], + "description": "Aggregation window (e.g. \"1h\", \"24h\")" + }, + "volume_usd": { + "type": [ + "number", + "null" + ], + "description": "Total trading volume in USD" + }, + "buy_volume_usd": { + "type": [ + "number", + "null" + ], + "description": "Buy volume in USD" + }, + "sell_volume_usd": { + "type": [ + "number", + "null" + ], + "description": "Sell volume in USD" + }, + "fees": { + "type": [ + "number", + "null" + ], + "description": "Total fees in USD" + }, + "txns": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "buys": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "sells": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "unique_traders": { + "type": [ + "integer", + "null" + ], + "format": "int64" + }, + "price_open": { + "type": [ + "number", + "null" + ], + "minimum": 0.0, + "maximum": 1.0 + }, + "price_close": { + "type": [ + "number", + "null" + ], + "minimum": 0.0, + "maximum": 1.0 + }, + "price_high": { + "type": [ + "number", + "null" + ], + "minimum": 0.0, + "maximum": 1.0 + }, + "price_low": { + "type": [ + "number", + "null" + ], + "minimum": 0.0, + "maximum": 1.0 + }, + "probability_open": { + "type": [ + "number", + "null" + ], + "minimum": 0.0, + "maximum": 1.0 + }, + "probability_close": { + "type": [ + "number", + "null" + ], + "minimum": 0.0, + "maximum": 1.0 + }, + "probability_high": { + "type": [ + "number", + "null" + ], + "minimum": 0.0, + "maximum": 1.0 + }, + "probability_low": { + "type": [ + "number", + "null" + ], + "minimum": 0.0, + "maximum": 1.0 + } + } + }, + "VolumeMilestonePayload": { + "type": "object", + "description": "Payload delivered when a market's trading volume crosses a USD milestone in the specified timeframe", + "required": [ + "condition_id", + "timeframe", + "milestone_usd", + "current_volume_usd", + "fees", + "txns" + ], + "properties": { + "condition_id": { + "type": "string", + "description": "Market condition ID" + }, + "timeframe": { + "type": "string", + "description": "Aggregation window that crossed the milestone (e.g. \"1h\", \"24h\")" + }, + "milestone_usd": { + "type": "number", + "description": "The USD milestone amount that was crossed" + }, + "current_volume_usd": { + "type": "number", + "description": "Current volume at time of trigger (USD)" + }, + "fees": { + "type": "number", + "description": "Total fees in USD for this timeframe" + }, + "txns": { + "type": "integer", + "format": "int64", + "description": "Total transactions in this timeframe" + } + } + }, + "EventVolumeMilestonePayload": { + "type": "object", + "description": "Payload delivered when an event's aggregated trading volume crosses a USD milestone", + "required": [ + "event_slug", + "timeframe", + "milestone_usd", + "current_volume_usd", + "fees", + "txns" + ], + "properties": { + "event_slug": { + "type": "string", + "description": "Event slug" + }, + "timeframe": { + "type": "string", + "description": "Aggregation window (e.g. \"1h\", \"24h\")" + }, + "milestone_usd": { + "type": "number", + "description": "The USD milestone amount that was crossed" + }, + "current_volume_usd": { + "type": "number", + "description": "Current aggregated event volume at time of trigger (USD)" + }, + "fees": { + "type": "number", + "description": "Total fees in USD for this timeframe" + }, + "txns": { + "type": "integer", + "format": "int64", + "description": "Total transactions in this timeframe" + } + } + }, + "PositionVolumeMilestonePayload": { + "type": "object", + "description": "Payload delivered when a position's trading volume crosses a USD milestone", + "required": [ + "position_id", + "timeframe", + "milestone_usd", + "current_volume_usd", + "buy_volume_usd", + "sell_volume_usd", + "fees", + "txns", + "buys", + "sells" + ], + "properties": { + "condition_id": { + "type": [ + "string", + "null" + ], + "description": "Parent market condition ID" + }, + "position_id": { + "type": "string", + "description": "ERC-1155 outcome token ID" + }, + "outcome": { + "type": [ + "string", + "null" + ], + "description": "Outcome name (e.g. \"Yes\", \"No\")" + }, + "outcome_index": { + "type": [ + "integer", + "null" + ], + "format": "int16", + "description": "Outcome index" + }, + "timeframe": { + "type": "string", + "description": "Aggregation window (e.g. \"1h\", \"24h\")" + }, + "milestone_usd": { + "type": "number", + "description": "The USD milestone amount that was crossed" + }, + "current_volume_usd": { + "type": "number", + "description": "Current position volume at time of trigger (USD)" + }, + "buy_volume_usd": { + "type": "number", + "description": "Buy volume in USD for this timeframe" + }, + "sell_volume_usd": { + "type": "number", + "description": "Sell volume in USD for this timeframe" + }, + "fees": { + "type": "number", + "description": "Total fees in USD" + }, + "txns": { + "type": "integer", + "format": "int64" + }, + "buys": { + "type": "integer", + "format": "int64" + }, + "sells": { + "type": "integer", + "format": "int64" + } + } + }, + "ProbabilitySpikePayload": { + "type": "object", + "required": [ + "position_id", + "previous_probability", + "current_probability", + "spike_direction", + "spike_pct" + ], + "properties": { + "position_id": { + "type": "string", + "description": "Outcome token ID" + }, + "condition_id": { + "type": [ + "string", + "null" + ], + "description": "Market condition ID" + }, + "event_slug": { + "type": [ + "string", + "null" + ], + "description": "Event slug" + }, + "outcome": { + "type": [ + "string", + "null" + ], + "description": "Outcome name (e.g. \"Yes\", \"No\")" + }, + "outcome_index": { + "type": [ + "integer", + "null" + ], + "format": "int16", + "description": "Outcome index" + }, + "previous_probability": { + "type": "number", + "description": "Probability at the start of the observation window (baseline snapshot, 0.0–1.0)" + }, + "current_probability": { + "type": "number", + "description": "Current probability that triggered the spike (0.0–1.0)" + }, + "spike_direction": { + "type": "string", + "enum": [ + "up", + "down" + ], + "description": "`\"up\"` = probability rising, `\"down\"` = probability falling" + }, + "spike_pct": { + "type": "number", + "description": "Percentage move that triggered this notification. Positive = up, negative = down." + } + } + }, + "PriceSpikePayload": { + "type": "object", + "required": [ + "position_id", + "previous_price", + "current_price", + "spike_direction", + "spike_pct" + ], + "properties": { + "position_id": { + "type": "string", + "description": "Outcome token ID" + }, + "condition_id": { + "type": [ + "string", + "null" + ], + "description": "Market condition ID" + }, + "event_slug": { + "type": [ + "string", + "null" + ], + "description": "Event slug" + }, + "outcome": { + "type": [ + "string", + "null" + ], + "description": "Outcome name (e.g. \"Yes\", \"No\")" + }, + "outcome_index": { + "type": [ + "integer", + "null" + ], + "format": "int16", + "description": "Outcome index" + }, + "previous_price": { + "type": "number", + "description": "Price at the start of the observation window (baseline snapshot, 0.0–1.0)" + }, + "current_price": { + "type": "number", + "description": "Current price that triggered the spike (0.0–1.0)" + }, + "spike_direction": { + "type": "string", + "enum": [ + "up", + "down" + ], + "description": "`\"up\"` = price rising, `\"down\"` = price falling" + }, + "spike_pct": { + "type": "number", + "description": "Percentage move that triggered this notification. Positive = up, negative = down." + } + } + }, + "MarketVolumeSpikePayload": { + "type": "object", + "description": "Payload delivered when a market's volume has spiked since the last snapshot", + "required": [ + "condition_id", + "timeframe", + "current_volume_usd", + "snapshot_volume_usd", + "delta_volume_usd", + "spike_pct", + "txns", + "fees" + ], + "properties": { + "condition_id": { + "type": "string", + "description": "Market condition ID" + }, + "timeframe": { + "type": "string", + "description": "Aggregation window (e.g. \"1h\", \"24h\")" + }, + "current_volume_usd": { + "type": "number", + "description": "Current volume at the time of the spike (USD)" + }, + "snapshot_volume_usd": { + "type": "number", + "description": "Volume at the snapshot baseline (USD)" + }, + "delta_volume_usd": { + "type": "number", + "description": "New volume since the snapshot that triggered this notification (USD)" + }, + "spike_pct": { + "type": "number", + "description": "Volume growth as a percentage of the snapshot (e.g. 200.0 means volume tripled)" + }, + "txns": { + "type": "integer", + "format": "int64", + "description": "Total transactions in this timeframe" + }, + "fees": { + "type": "number", + "description": "Total fees in USD for this timeframe" + } + } + }, + "EventVolumeSpikePayload": { + "type": "object", + "description": "Payload delivered when an event's aggregated volume has spiked since the last snapshot", + "required": [ + "event_slug", + "timeframe", + "current_volume_usd", + "snapshot_volume_usd", + "delta_volume_usd", + "spike_pct", + "txns", + "fees" + ], + "properties": { + "event_slug": { + "type": "string", + "description": "Event slug" + }, + "timeframe": { + "type": "string", + "description": "Aggregation window (e.g. \"1h\", \"24h\")" + }, + "current_volume_usd": { + "type": "number", + "description": "Current aggregated event volume at time of the spike (USD)" + }, + "snapshot_volume_usd": { + "type": "number", + "description": "Volume at the snapshot baseline (USD)" + }, + "delta_volume_usd": { + "type": "number", + "description": "New volume since the snapshot that triggered this notification (USD)" + }, + "spike_pct": { + "type": "number", + "description": "Volume growth as a percentage of the snapshot (e.g. 200.0 means volume tripled)" + }, + "txns": { + "type": "integer", + "format": "int64" + }, + "fees": { + "type": "number" + } + } + }, + "PositionVolumeSpikePayload": { + "type": "object", + "description": "Payload delivered when a position's volume has spiked since the last snapshot", + "required": [ + "position_id", + "condition_id", + "timeframe", + "current_volume_usd", + "snapshot_volume_usd", + "delta_volume_usd", + "spike_pct", + "txns", + "fees" + ], + "properties": { + "position_id": { + "type": "string", + "description": "ERC-1155 outcome token ID" + }, + "condition_id": { + "type": "string", + "description": "Parent market condition ID" + }, + "outcome": { + "type": [ + "string", + "null" + ], + "description": "Outcome name (e.g. \"Yes\", \"No\")" + }, + "outcome_index": { + "type": [ + "integer", + "null" + ], + "format": "int16" + }, + "timeframe": { + "type": "string", + "description": "Aggregation window (e.g. \"1h\", \"24h\")" + }, + "current_volume_usd": { + "type": "number", + "description": "Current position volume at the time of the spike (USD)" + }, + "snapshot_volume_usd": { + "type": "number", + "description": "Volume at the snapshot baseline (USD)" + }, + "delta_volume_usd": { + "type": "number", + "description": "New volume since the snapshot that triggered this notification (USD)" + }, + "spike_pct": { + "type": "number", + "description": "Volume growth as a percentage of the snapshot (e.g. 200.0 means volume tripled)" + }, + "txns": { + "type": "integer", + "format": "int64" + }, + "fees": { + "type": "number" + } + } + }, + "CloseToBondPayload": { + "type": "object", + "description": "Payload delivered when a trade occurs at a near-certain-outcome price", + "required": [ + "trader", + "taker", + "position_id", + "trade_id", + "hash", + "block", + "confirmed_at", + "amount_usd", + "shares_amount", + "fee", + "side", + "price", + "bond_side", + "threshold" + ], + "properties": { + "trader": { + "type": "string", + "description": "Limit-order maker wallet address (lowercase)" + }, + "taker": { + "type": "string", + "description": "Order filler wallet address (lowercase)" + }, + "position_id": { + "type": "string", + "description": "ERC-1155 outcome token ID" + }, + "condition_id": { + "type": [ + "string", + "null" + ], + "description": "Parent market condition ID" + }, + "outcome": { + "type": [ + "string", + "null" + ], + "description": "Outcome name (e.g. \"Yes\", \"No\")" + }, + "outcome_index": { + "type": [ + "integer", + "null" + ], + "description": "0 = Yes/Up, 1 = No" + }, + "question": { + "type": [ + "string", + "null" + ] + }, + "market_slug": { + "type": [ + "string", + "null" + ] + }, + "event_slug": { + "type": [ + "string", + "null" + ] + }, + "trade_id": { + "type": "string" + }, + "hash": { + "type": "string", + "description": "Transaction hash" + }, + "block": { + "type": "integer", + "format": "int64" + }, + "confirmed_at": { + "type": "integer", + "format": "int64", + "description": "Unix seconds" + }, + "amount_usd": { + "type": "number", + "description": "USD size of the trade" + }, + "shares_amount": { + "type": "number" + }, + "fee": { + "type": "number", + "description": "Fee paid in USD" + }, + "side": { + "type": "string", + "enum": [ + "Buy", + "Sell" + ] + }, + "price": { + "type": "number", + "minimum": 0.0, + "maximum": 1.0, + "description": "Price that triggered the notification (0.0–1.0)" + }, + "probability": { + "type": [ + "number", + "null" + ], + "minimum": 0.0, + "maximum": 1.0, + "description": "Implied probability (0.0–1.0)" + }, + "bond_side": { + "type": "string", + "enum": [ + "high", + "low" + ], + "description": "\"high\" when near YES (price ≥ threshold), \"low\" when near NO (price ≤ threshold)" + }, + "threshold": { + "type": "number", + "description": "The probability threshold from the subscription filter that was breached" + } + } + }, + "MarketCreatedOutcome": { + "type": "object", + "description": "An outcome entry within a newly created market", + "required": [ + "index", + "name", + "position_id" + ], + "properties": { + "index": { + "type": "integer", + "description": "Outcome index (0 = Yes, 1 = No)" + }, + "name": { + "type": "string", + "description": "Outcome name (e.g. \"Yes\", \"No\")" + }, + "position_id": { + "type": "string", + "description": "ERC-1155 position token ID for this outcome" + } + } + }, + "MarketCreatedPayload": { + "type": "object", + "description": "Payload delivered when a new prediction market is detected on-chain and enriched with Gamma API metadata", + "required": [ + "condition_id", + "market_slug", + "outcomes", + "question", + "description", + "tags", + "neg_risk" + ], + "properties": { + "condition_id": { + "type": "string", + "description": "Condition ID (0x-prefixed hex, lowercase)" + }, + "market_slug": { + "type": "string", + "description": "Market slug" + }, + "event_slug": { + "type": [ + "string", + "null" + ], + "description": "Parent event slug" + }, + "event_id": { + "type": [ + "string", + "null" + ], + "description": "Parent event ID" + }, + "event_title": { + "type": [ + "string", + "null" + ], + "description": "Parent event title" + }, + "series_slug": { + "type": [ + "string", + "null" + ], + "description": "Series slug (for recurring markets)" + }, + "outcomes": { + "type": "array", + "description": "List of market outcomes with their position IDs", + "items": { + "$ref": "#/components/schemas/MarketCreatedOutcome" + } + }, + "question": { + "type": "string", + "description": "Full market question text" + }, + "title": { + "type": [ + "string", + "null" + ], + "description": "Short display title" + }, + "description": { + "type": "string", + "description": "Market description" + }, + "category": { + "type": [ + "string", + "null" + ], + "description": "Market category (e.g. \"Sports\", \"Politics\")" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Market tags" + }, + "image_url": { + "type": [ + "string", + "null" + ], + "description": "Cover image URL" + }, + "neg_risk": { + "type": "boolean", + "description": "Whether this is a neg-risk market" + } + } + }, + "AssetPriceTickPayload": { + "type": "object", + "description": "Payload delivered on every raw Chainlink price tick for a tracked crypto asset", + "required": [ + "symbol", + "price", + "timestamp_ms" + ], + "properties": { + "symbol": { + "type": "string", + "enum": [ + "BTC", + "ETH", + "SOL", + "XRP", + "DOGE", + "BNB", + "HYPE" + ], + "description": "Asset symbol" + }, + "price": { + "type": "number", + "description": "Current asset price in USD from the Chainlink feed" + }, + "timestamp_ms": { + "type": "integer", + "format": "int64", + "description": "Tick timestamp (milliseconds since Unix epoch)" + } + } + }, + "AssetPriceWindowUpdatePayload": { + "type": "object", + "description": "Payload delivered twice per candle — once on open and once on close. `close_price` is 0.0 on the \"open\" update.", + "required": [ + "symbol", + "variant", + "start_time", + "end_time", + "open_price", + "close_price", + "update_type" + ], + "properties": { + "symbol": { + "type": "string", + "enum": [ + "BTC", + "ETH", + "SOL", + "XRP", + "DOGE", + "BNB", + "HYPE" + ], + "description": "Asset symbol" + }, + "variant": { + "type": "string", + "enum": [ + "5m", + "15m", + "1h", + "4h", + "1d", + "24h" + ], + "description": "Candle / window size" + }, + "start_time": { + "type": "integer", + "format": "int64", + "description": "Window start timestamp (milliseconds since Unix epoch)" + }, + "end_time": { + "type": "integer", + "format": "int64", + "description": "Window end timestamp (milliseconds since Unix epoch)" + }, + "open_price": { + "type": "number", + "description": "Opening price at start_time (USD)" + }, + "close_price": { + "type": "number", + "description": "Closing price at end_time (USD). 0.0 when update_type is \"open\" (not yet available)." + }, + "update_type": { + "type": "string", + "enum": [ + "open", + "close" + ], + "description": "\"open\" when the candle opens, \"close\" when it closes with a confirmed price" + } + } + }, + "TraderFirstTradeFilters": { + "type": "object", + "description": "Subscription filters for the `trader_first_trade` event. All fields are optional.", + "properties": { + "wallet_addresses": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Only fire for trades by these wallet addresses (lowercase). Empty = all traders." + }, + "condition_ids": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to trades in these markets. Empty = all markets." + }, + "event_slugs": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to trades in markets belonging to these events." + }, + "min_usd_value": { + "type": "number", + "description": "Minimum trade size in USD. Omit to match all sizes." + }, + "min_probability": { + "type": "number", + "minimum": 0.0, + "maximum": 1.0, + "description": "Only fire when the outcome probability is ≥ this value." + }, + "max_probability": { + "type": "number", + "minimum": 0.0, + "maximum": 1.0, + "description": "Only fire when the outcome probability is ≤ this value." + }, + "exclude_shortterm_markets": { + "type": "boolean", + "description": "When `true`, suppress webhooks for short-term \"updown\" markets (event slugs containing `updown`). Default: `false`." + } + } + }, + "TraderNewMarketFilters": { + "type": "object", + "description": "Subscription filters for the `trader_new_market` event. All fields are optional.", + "properties": { + "wallet_addresses": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Only fire for these wallet addresses (lowercase). Empty = all traders." + }, + "condition_ids": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to these markets." + }, + "event_slugs": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to markets belonging to these events." + }, + "exclude_shortterm_markets": { + "type": "boolean", + "description": "When `true`, suppress webhooks for short-term \"updown\" markets. Default: `false`." + } + } + }, + "TraderWhaleTradeFilters": { + "type": "object", + "description": "Subscription filters for the `trader_whale_trade` event. All fields are optional.", + "properties": { + "wallet_addresses": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Only fire for trades by these wallet addresses. Empty = all traders." + }, + "condition_ids": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to these markets." + }, + "event_slugs": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to markets belonging to these events." + }, + "min_usd_value": { + "type": "number", + "default": 0, + "description": "Minimum trade size in USD. Defaults to 0 (matches all trades)." + }, + "min_probability": { + "type": "number", + "minimum": 0.0, + "maximum": 1.0, + "description": "Only fire when outcome probability is ≥ this value." + }, + "max_probability": { + "type": "number", + "minimum": 0.0, + "maximum": 1.0, + "description": "Only fire when outcome probability is ≤ this value." + }, + "exclude_shortterm_markets": { + "type": "boolean", + "description": "When `true`, suppress webhooks for short-term \"updown\" markets. Default: `false`." + } + } + }, + "TraderNewTradeFilters": { + "type": "object", + "description": "Subscription filters for the `trader_new_trade` event. All fields are optional.", + "properties": { + "wallet_addresses": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Only fire for trades by these wallet addresses. Empty = all traders." + }, + "condition_ids": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to these markets." + }, + "event_slugs": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to markets belonging to these events." + }, + "min_usd_value": { + "type": "number", + "default": 0, + "description": "Minimum trade size in USD. Defaults to 0 (matches all trades)." + }, + "min_probability": { + "type": "number", + "minimum": 0.0, + "maximum": 1.0, + "description": "Only fire when outcome probability is ≥ this value." + }, + "max_probability": { + "type": "number", + "minimum": 0.0, + "maximum": 1.0, + "description": "Only fire when outcome probability is ≤ this value." + }, + "exclude_shortterm_markets": { + "type": "boolean", + "description": "When `true`, suppress webhooks for short-term \"updown\" markets. Default: `false`." + } + } + }, + "TraderGlobalPnlFilters": { + "type": "object", + "description": "Subscription filters for the `trader_global_pnl` event. All fields are optional.", + "properties": { + "traders": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Track only these trader wallet addresses. Empty = all traders." + }, + "min_realized_pnl_usd": { + "type": "number", + "description": "Only fire when realized PnL ≥ this value (USD). Use negative values for loss thresholds." + }, + "max_realized_pnl_usd": { + "type": "number", + "description": "Only fire when realized PnL ≤ this value (USD)." + }, + "min_volume_usd": { + "type": "number", + "description": "Only fire when total trading volume ≥ this value (USD)." + }, + "max_volume_usd": { + "type": "number", + "description": "Only fire when total trading volume ≤ this value (USD)." + }, + "min_buy_usd": { + "type": "number", + "description": "Only fire when buy volume ≥ this value (USD)." + }, + "min_sell_volume_usd": { + "type": "number", + "description": "Only fire when sell volume ≥ this value (USD)." + }, + "min_win_rate": { + "type": "number", + "minimum": 0.0, + "maximum": 100.0, + "description": "Only fire when market win rate ≥ this percentage (0.0–100.0)." + }, + "min_markets_traded": { + "type": "integer", + "format": "int64", + "description": "Only fire when the trader has traded in ≥ this many markets." + }, + "timeframes": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "1d", + "7d", + "30d", + "lifetime" + ] + }, + "description": "Restrict to these PnL windows. Empty = all windows." + } + } + }, + "TraderMarketPnlFilters": { + "type": "object", + "description": "Subscription filters for the `trader_market_pnl` event. All fields are optional.", + "properties": { + "traders": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Track only these trader wallet addresses." + }, + "condition_ids": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to these markets." + }, + "event_slugs": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to markets in these events." + }, + "min_realized_pnl_usd": { + "type": "number", + "description": "Only fire when per-market realized PnL ≥ this value (USD)." + }, + "max_realized_pnl_usd": { + "type": "number", + "description": "Only fire when per-market realized PnL ≤ this value (USD)." + }, + "min_volume_usd": { + "type": "number", + "description": "Only fire when total volume (buy + sell + redemption + merge) ≥ this value (USD)." + }, + "max_volume_usd": { + "type": "number", + "description": "Only fire when total volume ≤ this value (USD)." + }, + "min_buy_usd": { + "type": "number", + "description": "Only fire when buy volume in the market ≥ this value (USD)." + }, + "min_sell_volume_usd": { + "type": "number", + "description": "Only fire when sell volume in the market ≥ this value (USD)." + }, + "timeframes": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "1d", + "7d", + "30d", + "lifetime" + ] + }, + "description": "Restrict to these PnL windows." + }, + "exclude_shortterm_markets": { + "type": "boolean", + "description": "When `true`, suppress webhooks for short-term \"updown\" markets. Default: `false`." + } + } + }, + "TraderEventPnlFilters": { + "type": "object", + "description": "Subscription filters for the `trader_event_pnl` event. All fields are optional.", + "properties": { + "traders": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Track only these trader wallet addresses." + }, + "event_slugs": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to these events." + }, + "min_realized_pnl_usd": { + "type": "number", + "description": "Only fire when per-event realized PnL ≥ this value (USD)." + }, + "max_realized_pnl_usd": { + "type": "number", + "description": "Only fire when per-event realized PnL ≤ this value (USD)." + }, + "min_volume_usd": { + "type": "number", + "description": "Only fire when total event volume ≥ this value (USD)." + }, + "max_volume_usd": { + "type": "number", + "description": "Only fire when total event volume ≤ this value (USD)." + }, + "min_buy_usd": { + "type": "number", + "description": "Only fire when buy volume within the event ≥ this value (USD)." + }, + "min_sell_volume_usd": { + "type": "number", + "description": "Only fire when sell volume within the event ≥ this value (USD)." + }, + "min_markets_traded": { + "type": "integer", + "format": "int64", + "description": "Only fire when the trader has traded in ≥ this many markets within the event." + }, + "timeframes": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "1d", + "7d", + "30d", + "lifetime" + ] + }, + "description": "Restrict to these PnL windows." + }, + "exclude_shortterm_markets": { + "type": "boolean", + "description": "When `true`, suppress webhooks for short-term \"updown\" markets. Default: `false`." + } + } + }, + "MarketMetricsFilters": { + "type": "object", + "description": "Subscription filters for the `condition_metrics` event. All fields are optional.", + "properties": { + "condition_ids": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to these markets. Empty = all markets." + }, + "event_slugs": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to markets in these events." + }, + "timeframes": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "1m", + "5m", + "30m", + "1h", + "6h", + "24h", + "7d", + "30d" + ] + }, + "maxItems": 500, + "description": "Restrict to these aggregation windows. Empty = all windows." + }, + "min_volume_usd": { + "type": "number", + "description": "Only fire when volume ≥ this value (USD)." + }, + "max_volume_usd": { + "type": "number", + "description": "Only fire when volume ≤ this value (USD)." + }, + "min_txns": { + "type": "integer", + "format": "int64", + "description": "Only fire when transaction count ≥ this value." + }, + "min_unique_traders": { + "type": "integer", + "format": "int64", + "description": "Only fire when unique trader count ≥ this value." + }, + "min_fees": { + "type": "number", + "description": "Only fire when total fees ≥ this value (USD)." + } + } + }, + "EventMetricsFilters": { + "type": "object", + "description": "Subscription filters for the `event_metrics` event. All fields are optional.", + "properties": { + "event_slugs": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to these events. Empty = all events." + }, + "timeframes": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "1m", + "5m", + "30m", + "1h", + "6h", + "24h", + "7d", + "30d" + ] + }, + "maxItems": 500, + "description": "Restrict to these aggregation windows." + }, + "min_volume_usd": { + "type": "number", + "description": "Only fire when aggregated event volume ≥ this value (USD)." + }, + "max_volume_usd": { + "type": "number" + }, + "min_txns": { + "type": "integer", + "format": "int64" + }, + "min_unique_traders": { + "type": "integer", + "format": "int64" + }, + "min_fees": { + "type": "number" + }, + "exclude_shortterm_markets": { + "type": "boolean", + "description": "When `true`, suppress webhooks for short-term \"updown\" markets. Default: `false`." + } + } + }, + "PositionMetricsFilters": { + "type": "object", + "description": "Subscription filters for the `position_metrics` event. All fields are optional.", + "properties": { + "position_ids": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to these outcome token IDs." + }, + "condition_ids": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to positions within these markets." + }, + "outcomes": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to positions with these outcome names (e.g. [\"Yes\", \"No\"])." + }, + "timeframes": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "1m", + "5m", + "30m", + "1h", + "6h", + "24h", + "7d", + "30d" + ] + }, + "maxItems": 500, + "description": "Restrict to these aggregation windows." + }, + "min_volume_usd": { + "type": "number", + "description": "Only fire when position volume ≥ this value (USD)." + }, + "max_volume_usd": { + "type": "number" + }, + "min_buy_usd": { + "type": "number" + }, + "min_sell_volume_usd": { + "type": "number" + }, + "min_txns": { + "type": "integer", + "format": "int64" + }, + "min_unique_traders": { + "type": "integer", + "format": "int64" + }, + "min_price_change_pct": { + "type": "number", + "description": "Only fire when price change % ≥ this value." + }, + "min_probability_change_pct": { + "type": "number", + "description": "Only fire when probability change % ≥ this value." + }, + "min_fees": { + "type": "number" + } + } + }, + "MarketVolumeMilestoneFilters": { + "type": "object", + "description": "Subscription filters for the `market_volume_milestone` event.", + "required": [ + "timeframes" + ], + "properties": { + "timeframes": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "1m", + "5m", + "30m", + "1h", + "6h", + "24h", + "7d", + "30d" + ] + }, + "minItems": 1, + "maxItems": 500, + "description": "**Required.** Aggregation windows to monitor (e.g. [\"1h\", \"24h\"])." + }, + "condition_ids": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to these markets. Empty = all markets." + }, + "milestone_amounts": { + "type": "array", + "items": { + "type": "integer", + "format": "int64" + }, + "maxItems": 500, + "description": "Specific USD milestones to trigger on (e.g. [10000, 100000, 1000000]). Empty = all milestones." + } + } + }, + "EventVolumeMilestoneFilters": { + "type": "object", + "description": "Subscription filters for the `event_volume_milestone` event.", + "required": [ + "timeframes" + ], + "properties": { + "timeframes": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "1m", + "5m", + "30m", + "1h", + "6h", + "24h", + "7d", + "30d" + ] + }, + "minItems": 1, + "maxItems": 500, + "description": "**Required.** Aggregation windows to monitor." + }, + "event_slugs": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to these events." + }, + "milestone_amounts": { + "type": "array", + "items": { + "type": "integer", + "format": "int64" + }, + "maxItems": 500, + "description": "Specific USD milestones to trigger on." + }, + "exclude_shortterm_markets": { + "type": "boolean", + "description": "When `true`, suppress webhooks for short-term \"updown\" markets. Default: `false`." + } + } + }, + "PositionVolumeMilestoneFilters": { + "type": "object", + "description": "Subscription filters for the `position_volume_milestone` event.", + "required": [ + "timeframes" + ], + "properties": { + "timeframes": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "1m", + "5m", + "30m", + "1h", + "6h", + "24h", + "7d", + "30d" + ] + }, + "minItems": 1, + "maxItems": 500, + "description": "**Required.** Aggregation windows to monitor." + }, + "position_ids": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to these outcome token IDs." + }, + "condition_ids": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to positions within these markets." + }, + "milestone_amounts": { + "type": "array", + "items": { + "type": "integer", + "format": "int64" + }, + "maxItems": 500, + "description": "Specific USD milestones to trigger on." + } + } + }, + "ProbabilitySpikeFilters": { + "type": "object", + "description": "Subscription filters for the `probability_spike` event.", + "properties": { + "position_ids": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to specific outcome token IDs. Empty = all positions." + }, + "condition_ids": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to specific market condition IDs. Empty = all markets." + }, + "event_slugs": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to specific events. Empty = all events." + }, + "outcomes": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to these outcome names (e.g. [\"Yes\", \"No\"])." + }, + "min_probability_change_pct": { + "type": "number", + "description": "Minimum probability percentage move to trigger (e.g. `10` for a 10% move)." + }, + "spike_direction": { + "type": "string", + "enum": [ + "up", + "down", + "both" + ], + "description": "`\"up\"` = probability rising only (default when omitted), `\"down\"` = falling only, `\"both\"` = either direction." + }, + "window_secs": { + "type": "integer", + "minimum": 1, + "maximum": 600, + "description": "Observation window in seconds. The first trade in each window sets the reference price; subsequent trades are compared to it. E.g. `60` detects moves that occur within 60 seconds." + }, + "exclude_shortterm_markets": { + "type": "boolean", + "description": "When `true`, suppress webhooks for short-term \"updown\" markets. Default: `false`." + } + } + }, + "PriceSpikeFilters": { + "type": "object", + "description": "Subscription filters for the `price_spike` event.", + "properties": { + "position_ids": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to specific outcome token IDs. Empty = all positions." + }, + "condition_ids": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to specific market condition IDs. Empty = all markets." + }, + "event_slugs": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to specific events. Empty = all events." + }, + "outcomes": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to these outcome names (e.g. [\"Yes\", \"No\"])." + }, + "min_price_change_pct": { + "type": "number", + "description": "Minimum price percentage move to trigger (e.g. `10` for a 10% move)." + }, + "spike_direction": { + "type": "string", + "enum": [ + "up", + "down", + "both" + ], + "description": "`\"up\"` = price rising only (default when omitted), `\"down\"` = falling only, `\"both\"` = either direction." + }, + "window_secs": { + "type": "integer", + "minimum": 1, + "maximum": 600, + "description": "Observation window in seconds. The first trade in each window sets the reference price; subsequent trades are compared to it. E.g. `60` detects moves that occur within 60 seconds." + }, + "exclude_shortterm_markets": { + "type": "boolean", + "description": "When `true`, suppress webhooks for short-term \"updown\" markets. Default: `false`." + } + } + }, + "MarketVolumeSpikeFilters": { + "type": "object", + "description": "Subscription filters for the `market_volume_spike` event. `spike_ratio` is required.", + "required": [ + "spike_ratio" + ], + "properties": { + "spike_ratio": { + "type": "number", + "exclusiveMinimum": 1.0, + "description": "**Required.** Multiplier threshold (must be > 1.0). Fires when current volume >= snapshot × ratio. The snapshot is set automatically on first data and resets after each fire." + }, + "window_secs": { + "type": "integer", + "minimum": 1, + "maximum": 600, + "description": "Force snapshot reset after this many seconds (max 600 / 10 minutes)." + }, + "condition_ids": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to these markets. Empty = all markets." + }, + "timeframes": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "1m", + "5m", + "30m", + "1h", + "6h", + "1d", + "24h", + "7d", + "30d" + ] + }, + "maxItems": 500, + "description": "Restrict to these aggregation windows. Empty = all windows." + } + } + }, + "EventVolumeSpikeFilters": { + "type": "object", + "description": "Subscription filters for the `event_volume_spike` event. `spike_ratio` is required.", + "required": [ + "spike_ratio" + ], + "properties": { + "spike_ratio": { + "type": "number", + "exclusiveMinimum": 1.0, + "description": "**Required.** Multiplier threshold (must be > 1.0). Fires when current volume >= snapshot × ratio." + }, + "window_secs": { + "type": "integer", + "minimum": 1, + "maximum": 600, + "description": "Force snapshot reset after this many seconds (max 600 / 10 minutes)." + }, + "event_slugs": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to these events." + }, + "timeframes": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "1m", + "5m", + "30m", + "1h", + "6h", + "1d", + "24h", + "7d", + "30d" + ] + }, + "maxItems": 500, + "description": "Restrict to these aggregation windows." + }, + "exclude_shortterm_markets": { + "type": "boolean", + "description": "When `true`, suppress webhooks for short-term \"updown\" markets. Default: `false`." + } + } + }, + "PositionVolumeSpikeFilters": { + "type": "object", + "description": "Subscription filters for the `position_volume_spike` event. `spike_ratio` is required.", + "required": [ + "spike_ratio" + ], + "properties": { + "spike_ratio": { + "type": "number", + "exclusiveMinimum": 1.0, + "description": "**Required.** Multiplier threshold (must be > 1.0). Fires when current volume >= snapshot × ratio." + }, + "window_secs": { + "type": "integer", + "minimum": 1, + "maximum": 600, + "description": "Force snapshot reset after this many seconds (max 600 / 10 minutes)." + }, + "position_ids": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to these outcome token IDs." + }, + "condition_ids": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to positions within these markets." + }, + "outcomes": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to these outcome names." + }, + "timeframes": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "1m", + "5m", + "30m", + "1h", + "6h", + "1d", + "24h", + "7d", + "30d" + ] + }, + "maxItems": 500, + "description": "Restrict to these aggregation windows." + } + } + }, + "CloseToBondFilters": { + "type": "object", + "description": "Subscription filters for the `close_to_bond` event. At least one of `min_probability` or `max_probability` is required.", + "anyOf": [ + { + "required": [ + "min_probability" + ] + }, + { + "required": [ + "max_probability" + ] + } + ], + "properties": { + "min_probability": { + "type": "number", + "minimum": 0.0, + "maximum": 1.0, + "description": "Trigger when the YES outcome price is ≥ this value (e.g. 0.95 for 95% certainty). At least one of `min_probability` or `max_probability` must be set." + }, + "max_probability": { + "type": "number", + "minimum": 0.0, + "maximum": 1.0, + "description": "Trigger when the YES outcome price is ≤ this value (e.g. 0.05 for near-certain NO)." + }, + "condition_ids": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to these markets." + }, + "position_ids": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to these outcome token IDs." + }, + "event_slugs": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to markets in these events." + }, + "outcomes": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to these outcome names (e.g. [\"Yes\", \"No\"])." + }, + "position_outcome_indices": { + "type": "array", + "items": { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "maxItems": 500, + "description": "Restrict by outcome index. 0 = Yes/Up, 1 = No. Position 0 usually represents the Up/Yes side in binary markets." + }, + "exclude_shortterm_markets": { + "type": "boolean", + "description": "When `true`, suppress webhooks for short-term \"updown\" markets. Default: `false`." + } + } + }, + "MarketCreatedFilters": { + "type": "object", + "description": "Subscription filters for the `market_created` event. All fields are optional.", + "properties": { + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to markets with these tags or category names (case-insensitive match)." + }, + "condition_ids": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to these specific markets." + }, + "event_slugs": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 500, + "description": "Restrict to markets belonging to these events." + }, + "exclude_shortterm_markets": { + "type": "boolean", + "description": "When `true`, suppress webhooks for short-term \"updown\" markets (event slugs containing `updown`). Default: `false`." + } + } + }, + "AssetPriceTickFilters": { + "type": "object", + "description": "Subscription filters for the `asset_price_tick` event. All fields are optional.", + "properties": { + "asset_symbols": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "BTC", + "ETH", + "SOL", + "XRP", + "DOGE", + "BNB", + "HYPE" + ] + }, + "description": "Restrict to these crypto assets. Empty = all assets." + } + } + }, + "AssetPriceWindowUpdateFilters": { + "type": "object", + "description": "Subscription filters for the `asset_price_window_update` event. All fields are optional.", + "properties": { + "asset_symbols": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "BTC", + "ETH", + "SOL", + "XRP", + "DOGE", + "BNB", + "HYPE" + ] + }, + "maxItems": 500, + "description": "Restrict to these crypto assets. Empty = all assets." + }, + "timeframes": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "5m", + "15m", + "1h", + "4h", + "1d", + "24h" + ] + }, + "maxItems": 500, + "description": "Restrict to these candle sizes. Empty = all sizes." + } + } + }, + "WsAlertEventType": { + "type": "string", + "description": "All alert event types supported by both HTTP webhooks and the alerts WebSocket.", + "enum": [ + "trader_first_trade", + "trader_new_market", + "trader_whale_trade", + "trader_new_trade", + "trader_global_pnl", + "trader_market_pnl", + "trader_event_pnl", + "condition_metrics", + "event_metrics", + "position_metrics", + "market_volume_milestone", + "event_volume_milestone", + "position_volume_milestone", + "probability_spike", + "price_spike", + "market_volume_spike", + "event_volume_spike", + "position_volume_spike", + "close_to_bond", + "market_created", + "asset_price_tick", + "asset_price_window_update" + ] + }, + "WsAlertSubscribedResponse": { + "type": "object", + "required": [ + "op", + "event", + "subscription_id" + ], + "description": "Server acknowledgement for a successful alert subscription.", + "properties": { + "op": { + "type": "string", + "enum": [ + "subscribed" + ] + }, + "event": { + "$ref": "#/components/schemas/WsAlertEventType" + }, + "subscription_id": { + "type": "string", + "format": "uuid" + } + } + }, + "WsAlertUnsubscribedResponse": { + "type": "object", + "required": [ + "op", + "event" + ], + "description": "Server acknowledgement for a successful alert unsubscription.", + "properties": { + "op": { + "type": "string", + "enum": [ + "unsubscribed" + ] + }, + "event": { + "$ref": "#/components/schemas/WsAlertEventType" + } + } + }, + "WsAlertErrorResponse": { + "type": "object", + "required": [ + "error" + ], + "description": "Error returned by the alerts WebSocket when a message is invalid or a subscription request fails.", + "properties": { + "error": { + "type": "string" + } + } + }, + "WsAlertTraderFirstTradeSubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Subscribe to `trader_first_trade` alerts. Fired when a tracked trader executes their first trade on Polymarket", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "subscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "trader_first_trade" + ] + } + }, + "example": { + "op": "subscribe", + "event": "trader_first_trade", + "wallet_addresses": [ + "0x0000000000000000000000000000000000000000" + ], + "min_usd_value": 10000.0, + "min_probability": 0.95, + "max_probability": 0.05, + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "event_slugs": [ + "example-event" + ], + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/TraderFirstTradeFilters" + } + ] + }, + "WsAlertTraderFirstTradeUnsubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Unsubscribe from `trader_first_trade` alerts. The filter fields must match the original subscription exactly.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "unsubscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "trader_first_trade" + ] + } + }, + "example": { + "op": "unsubscribe", + "event": "trader_first_trade", + "wallet_addresses": [ + "0x0000000000000000000000000000000000000000" + ], + "min_usd_value": 10000.0, + "min_probability": 0.95, + "max_probability": 0.05, + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "event_slugs": [ + "example-event" + ], + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/TraderFirstTradeFilters" + } + ] + }, + "WsAlertTraderFirstTradeEvent": { + "type": "object", + "required": [ + "event", + "timestamp", + "data" + ], + "description": "Pushed `trader_first_trade` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "properties": { + "event": { + "type": "string", + "enum": [ + "trader_first_trade" + ] + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix timestamp in milliseconds" + }, + "data": { + "$ref": "#/components/schemas/FirstTradePayload" + } + }, + "example": { + "event": "trader_first_trade", + "timestamp": 1743500000000, + "data": { + "trader": "0x0000000000000000000000000000000000000000", + "taker": "0x0000000000000000000000000000000000000000", + "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", + "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + "outcome": "Yes", + "outcome_index": 0, + "question": "Will this test webhook fire correctly?", + "market_slug": "test-market-0000000000", + "event_slug": "test-event-0000000000", + "trade_id": "00000000-0000-0000-0000-000000000000", + "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "block": 0, + "confirmed_at": 1700000000, + "amount_usd": 125.0, + "shares_amount": 250.0, + "fee": 0.125, + "side": "Buy", + "price": 0.5, + "exchange": "polymarket", + "trade_type": "OrderFilled" + } + } + }, + "WsAlertTraderNewMarketSubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Subscribe to `trader_new_market` alerts. Fired when a trader places their first trade in a specific market/condition (fires once per trader+market pair)", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "subscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "trader_new_market" + ] + } + }, + "example": { + "op": "subscribe", + "event": "trader_new_market", + "wallet_addresses": [ + "0x0000000000000000000000000000000000000000" + ], + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "event_slugs": [ + "example-event" + ], + "min_usd_value": 10000.0, + "min_probability": 0.95, + "max_probability": 0.05, + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/TraderNewMarketFilters" + } + ] + }, + "WsAlertTraderNewMarketUnsubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Unsubscribe from `trader_new_market` alerts. The filter fields must match the original subscription exactly.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "unsubscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "trader_new_market" + ] + } + }, + "example": { + "op": "unsubscribe", + "event": "trader_new_market", + "wallet_addresses": [ + "0x0000000000000000000000000000000000000000" + ], + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "event_slugs": [ + "example-event" + ], + "min_usd_value": 10000.0, + "min_probability": 0.95, + "max_probability": 0.05, + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/TraderNewMarketFilters" + } + ] + }, + "WsAlertTraderNewMarketEvent": { + "type": "object", + "required": [ + "event", + "timestamp", + "data" + ], + "description": "Pushed `trader_new_market` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "properties": { + "event": { + "type": "string", + "enum": [ + "trader_new_market" + ] + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix timestamp in milliseconds" + }, + "data": { + "$ref": "#/components/schemas/NewMarketPayload" + } + }, + "example": { + "event": "trader_new_market", + "timestamp": 1743500000000, + "data": { + "trader": "0x0000000000000000000000000000000000000000", + "taker": "0x0000000000000000000000000000000000000000", + "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", + "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + "outcome": "Yes", + "outcome_index": 0, + "question": "Will this test webhook fire correctly?", + "market_slug": "test-market-0000000000", + "event_slug": "test-event-0000000000", + "trade_id": "00000000-0000-0000-0000-000000000000", + "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "block": 0, + "confirmed_at": 1700000000, + "amount_usd": 125.0, + "shares_amount": 250.0, + "fee": 0.125, + "side": "Buy", + "price": 0.5, + "probability": 0.5, + "exchange": "polymarket", + "trade_type": "OrderFilled" + } + } + }, + "WsAlertTraderWhaleTradeSubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Subscribe to `trader_whale_trade` alerts. Fired when a trade meets the configured criteria. Use `min_usd_value` to filter by minimum trade size (optional, defaults to 0 — matches all trades), and `min_probability`/`max_probability` to restrict to a probability range.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "subscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "trader_whale_trade" + ] + } + }, + "example": { + "op": "subscribe", + "event": "trader_whale_trade", + "wallet_addresses": [ + "0x0000000000000000000000000000000000000000" + ], + "min_usd_value": 10000.0, + "min_probability": 0.95, + "max_probability": 0.05, + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "event_slugs": [ + "example-event" + ], + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/TraderWhaleTradeFilters" + } + ] + }, + "WsAlertTraderWhaleTradeUnsubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Unsubscribe from `trader_whale_trade` alerts. The filter fields must match the original subscription exactly.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "unsubscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "trader_whale_trade" + ] + } + }, + "example": { + "op": "unsubscribe", + "event": "trader_whale_trade", + "wallet_addresses": [ + "0x0000000000000000000000000000000000000000" + ], + "min_usd_value": 10000.0, + "min_probability": 0.95, + "max_probability": 0.05, + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "event_slugs": [ + "example-event" + ], + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/TraderWhaleTradeFilters" + } + ] + }, + "WsAlertTraderWhaleTradeEvent": { + "type": "object", + "required": [ + "event", + "timestamp", + "data" + ], + "description": "Pushed `trader_whale_trade` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "properties": { + "event": { + "type": "string", + "enum": [ + "trader_whale_trade" + ] + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix timestamp in milliseconds" + }, + "data": { + "$ref": "#/components/schemas/WhaleTradePayload" + } + }, + "example": { + "event": "trader_whale_trade", + "timestamp": 1743500000000, + "data": { + "trader": "0x0000000000000000000000000000000000000000", + "taker": "0x0000000000000000000000000000000000000000", + "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", + "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + "outcome": "Yes", + "outcome_index": 0, + "question": "Will this test webhook fire correctly?", + "market_slug": "test-market-0000000000", + "event_slug": "test-event-0000000000", + "trade_id": "00000000-0000-0000-0000-000000000000", + "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "block": 0, + "confirmed_at": 1700000000, + "amount_usd": 125.0, + "shares_amount": 250.0, + "fee": 0.125, + "side": "Buy", + "price": 0.5, + "probability": 0.5, + "exchange": "polymarket", + "trade_type": "OrderFilled" + } + } + }, + "WsAlertTraderNewTradeSubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Subscribe to `trader_new_trade` alerts. Fired on every order-filled trade. Use `wallet_addresses` to watch specific traders, `min_usd_value` to filter by size, and `min_probability`/`max_probability` to restrict to a probability range.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "subscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "trader_new_trade" + ] + } + }, + "example": { + "op": "subscribe", + "event": "trader_new_trade", + "wallet_addresses": [ + "0x0000000000000000000000000000000000000000" + ], + "min_usd_value": 10000.0, + "min_probability": 0.95, + "max_probability": 0.05, + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "event_slugs": [ + "example-event" + ], + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/TraderNewTradeFilters" + } + ] + }, + "WsAlertTraderNewTradeUnsubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Unsubscribe from `trader_new_trade` alerts. The filter fields must match the original subscription exactly.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "unsubscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "trader_new_trade" + ] + } + }, + "example": { + "op": "unsubscribe", + "event": "trader_new_trade", + "wallet_addresses": [ + "0x0000000000000000000000000000000000000000" + ], + "min_usd_value": 10000.0, + "min_probability": 0.95, + "max_probability": 0.05, + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "event_slugs": [ + "example-event" + ], + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/TraderNewTradeFilters" + } + ] + }, + "WsAlertTraderNewTradeEvent": { + "type": "object", + "required": [ + "event", + "timestamp", + "data" + ], + "description": "Pushed `trader_new_trade` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "properties": { + "event": { + "type": "string", + "enum": [ + "trader_new_trade" + ] + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix timestamp in milliseconds" + }, + "data": { + "$ref": "#/components/schemas/NewTradePayload" + } + }, + "example": { + "event": "trader_new_trade", + "timestamp": 1743500000000, + "data": { + "trader": "0x0000000000000000000000000000000000000000", + "taker": "0x0000000000000000000000000000000000000000", + "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", + "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + "outcome": "Yes", + "outcome_index": 0, + "question": "Will this test webhook fire correctly?", + "market_slug": "test-market-0000000000", + "event_slug": "test-event-0000000000", + "trade_id": "00000000-0000-0000-0000-000000000000", + "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "block": 0, + "confirmed_at": 1700000000, + "amount_usd": 25.0, + "shares_amount": 50.0, + "fee": 0.025, + "side": "Buy", + "price": 0.5, + "probability": 0.5, + "exchange": "polymarket", + "trade_type": "OrderFilled" + } + } + }, + "WsAlertTraderGlobalPnlSubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Subscribe to `trader_global_pnl` alerts. Fired when a trader's global PnL crosses a configured threshold", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "subscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "trader_global_pnl" + ] + } + }, + "example": { + "op": "subscribe", + "event": "trader_global_pnl", + "traders": [ + "0x0000000000000000000000000000000000000000" + ], + "min_realized_pnl_usd": 1000.0, + "max_realized_pnl_usd": 5000.0, + "min_volume_usd": 10000.0, + "max_volume_usd": 100000.0, + "min_buy_usd": 5000.0, + "min_sell_volume_usd": 2500.0, + "min_win_rate": 60.0, + "min_markets_traded": 5, + "timeframes": [ + "1h" + ] + } + }, + { + "$ref": "#/components/schemas/TraderGlobalPnlFilters" + } + ] + }, + "WsAlertTraderGlobalPnlUnsubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Unsubscribe from `trader_global_pnl` alerts. The filter fields must match the original subscription exactly.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "unsubscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "trader_global_pnl" + ] + } + }, + "example": { + "op": "unsubscribe", + "event": "trader_global_pnl", + "traders": [ + "0x0000000000000000000000000000000000000000" + ], + "min_realized_pnl_usd": 1000.0, + "max_realized_pnl_usd": 5000.0, + "min_volume_usd": 10000.0, + "max_volume_usd": 100000.0, + "min_buy_usd": 5000.0, + "min_sell_volume_usd": 2500.0, + "min_win_rate": 60.0, + "min_markets_traded": 5, + "timeframes": [ + "1h" + ] + } + }, + { + "$ref": "#/components/schemas/TraderGlobalPnlFilters" + } + ] + }, + "WsAlertTraderGlobalPnlEvent": { + "type": "object", + "required": [ + "event", + "timestamp", + "data" + ], + "description": "Pushed `trader_global_pnl` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "properties": { + "event": { + "type": "string", + "enum": [ + "trader_global_pnl" + ] + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix timestamp in milliseconds" + }, + "data": { + "$ref": "#/components/schemas/GlobalPnlPayload" + } + }, + "example": { + "event": "trader_global_pnl", + "timestamp": 1743500000000, + "data": { + "trader": "0x0000000000000000000000000000000000000000", + "timeframe": "7d", + "realized_pnl_usd": 250.0, + "events_traded": 3, + "markets_traded": 5, + "total_buys": 12, + "total_sells": 8, + "total_redemptions": 1, + "total_merges": 0, + "total_volume_usd": 1500.0, + "buy_volume_usd": 900.0, + "sell_volume_usd": 600.0, + "redemption_volume_usd": 50.0, + "merge_volume_usd": 0.0, + "markets_won": 3, + "markets_lost": 2, + "market_win_rate_pct": 60.0, + "avg_pnl_per_market": 50.0, + "avg_pnl_per_trade": 12.5, + "avg_hold_time_seconds": 86400.0, + "total_fees": 7.5, + "best_trade_pnl_usd": 180.0, + "best_trade_condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + "first_trade_at": 1700000000, + "last_trade_at": 1700000000 + } + } + }, + "WsAlertTraderMarketPnlSubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Subscribe to `trader_market_pnl` alerts. Fired when a trader's market-level PnL crosses a configured threshold", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "subscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "trader_market_pnl" + ] + } + }, + "example": { + "op": "subscribe", + "event": "trader_market_pnl", + "traders": [ + "0x0000000000000000000000000000000000000000" + ], + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "event_slugs": [ + "example-event" + ], + "min_realized_pnl_usd": 1000.0, + "max_realized_pnl_usd": 5000.0, + "min_volume_usd": 10000.0, + "max_volume_usd": 100000.0, + "min_buy_usd": 5000.0, + "min_sell_volume_usd": 2500.0, + "timeframes": [ + "1h" + ], + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/TraderMarketPnlFilters" + } + ] + }, + "WsAlertTraderMarketPnlUnsubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Unsubscribe from `trader_market_pnl` alerts. The filter fields must match the original subscription exactly.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "unsubscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "trader_market_pnl" + ] + } + }, + "example": { + "op": "unsubscribe", + "event": "trader_market_pnl", + "traders": [ + "0x0000000000000000000000000000000000000000" + ], + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "event_slugs": [ + "example-event" + ], + "min_realized_pnl_usd": 1000.0, + "max_realized_pnl_usd": 5000.0, + "min_volume_usd": 10000.0, + "max_volume_usd": 100000.0, + "min_buy_usd": 5000.0, + "min_sell_volume_usd": 2500.0, + "timeframes": [ + "1h" + ], + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/TraderMarketPnlFilters" + } + ] + }, + "WsAlertTraderMarketPnlEvent": { + "type": "object", + "required": [ + "event", + "timestamp", + "data" + ], + "description": "Pushed `trader_market_pnl` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "properties": { + "event": { + "type": "string", + "enum": [ + "trader_market_pnl" + ] + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix timestamp in milliseconds" + }, + "data": { + "$ref": "#/components/schemas/MarketPnlPayload" + } + }, + "example": { + "event": "trader_market_pnl", + "timestamp": 1743500000000, + "data": { + "trader": "0x0000000000000000000000000000000000000000", + "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + "event_slug": "test-event-0000000000", + "timeframe": "7d", + "outcomes_traded": 2, + "total_buys": 4, + "total_sells": 3, + "total_redemptions": 1, + "total_merges": 0, + "buy_usd": 300.0, + "sell_usd": 200.0, + "redemption_usd": 50.0, + "merge_usd": 0.0, + "realized_pnl_usd": 100.0, + "winning_outcomes": 1, + "total_fees": 2.5, + "first_trade_at": 1700000000, + "last_trade_at": 1700000000 + } + } + }, + "WsAlertTraderEventPnlSubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Subscribe to `trader_event_pnl` alerts. Fired when a trader's event-level PnL crosses a configured threshold", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "subscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "trader_event_pnl" + ] + } + }, + "example": { + "op": "subscribe", + "event": "trader_event_pnl", + "traders": [ + "0x0000000000000000000000000000000000000000" + ], + "event_slugs": [ + "example-event" + ], + "min_realized_pnl_usd": 1000.0, + "max_realized_pnl_usd": 5000.0, + "min_volume_usd": 10000.0, + "max_volume_usd": 100000.0, + "min_buy_usd": 5000.0, + "min_sell_volume_usd": 2500.0, + "min_markets_traded": 5, + "timeframes": [ + "1h" + ], + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/TraderEventPnlFilters" + } + ] + }, + "WsAlertTraderEventPnlUnsubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Unsubscribe from `trader_event_pnl` alerts. The filter fields must match the original subscription exactly.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "unsubscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "trader_event_pnl" + ] + } + }, + "example": { + "op": "unsubscribe", + "event": "trader_event_pnl", + "traders": [ + "0x0000000000000000000000000000000000000000" + ], + "event_slugs": [ + "example-event" + ], + "min_realized_pnl_usd": 1000.0, + "max_realized_pnl_usd": 5000.0, + "min_volume_usd": 10000.0, + "max_volume_usd": 100000.0, + "min_buy_usd": 5000.0, + "min_sell_volume_usd": 2500.0, + "min_markets_traded": 5, + "timeframes": [ + "1h" + ], + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/TraderEventPnlFilters" + } + ] + }, + "WsAlertTraderEventPnlEvent": { + "type": "object", + "required": [ + "event", + "timestamp", + "data" + ], + "description": "Pushed `trader_event_pnl` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "properties": { + "event": { + "type": "string", + "enum": [ + "trader_event_pnl" + ] + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix timestamp in milliseconds" + }, + "data": { + "$ref": "#/components/schemas/EventPnlPayload" + } + }, + "example": { + "event": "trader_event_pnl", + "timestamp": 1743500000000, + "data": { + "trader": "0x0000000000000000000000000000000000000000", + "event_slug": "test-event-0000000000", + "timeframe": "7d", + "markets_traded": 2, + "outcomes_traded": 3, + "total_buys": 6, + "total_sells": 4, + "total_redemptions": 1, + "total_merges": 0, + "total_volume_usd": 800.0, + "buy_usd": 480.0, + "sell_usd": 320.0, + "redemption_usd": 50.0, + "merge_usd": 0.0, + "realized_pnl_usd": 150.0, + "winning_markets": 1, + "losing_markets": 1, + "total_fees": 4.0, + "first_trade_at": 1700000000, + "last_trade_at": 1700000000 + } + } + }, + "WsAlertConditionMetricsSubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Subscribe to `condition_metrics` alerts. Fired when a market's volume or transaction metrics cross a configured threshold. Use `timeframes` to restrict to specific windows (valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`).", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "subscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "condition_metrics" + ] + } + }, + "example": { + "op": "subscribe", + "event": "condition_metrics", + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "min_volume_usd": 10000.0, + "max_volume_usd": 100000.0, + "min_fees": 100.0, + "min_txns": 10, + "min_unique_traders": 10, + "timeframes": [ + "1h" + ] + } + }, + { + "$ref": "#/components/schemas/MarketMetricsFilters" + } + ] + }, + "WsAlertConditionMetricsUnsubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Unsubscribe from `condition_metrics` alerts. The filter fields must match the original subscription exactly.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "unsubscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "condition_metrics" + ] + } + }, + "example": { + "op": "unsubscribe", + "event": "condition_metrics", + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "min_volume_usd": 10000.0, + "max_volume_usd": 100000.0, + "min_fees": 100.0, + "min_txns": 10, + "min_unique_traders": 10, + "timeframes": [ + "1h" + ] + } + }, + { + "$ref": "#/components/schemas/MarketMetricsFilters" + } + ] + }, + "WsAlertConditionMetricsEvent": { + "type": "object", + "required": [ + "event", + "timestamp", + "data" + ], + "description": "Pushed `condition_metrics` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "properties": { + "event": { + "type": "string", + "enum": [ + "condition_metrics" + ] + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix timestamp in milliseconds" + }, + "data": { + "$ref": "#/components/schemas/ConditionMetricsPayload" + } + }, + "example": { + "event": "condition_metrics", + "timestamp": 1743500000000, + "data": { + "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + "timeframe": "1h", + "volume_usd": 50000.0, + "fees": 250.0, + "txns": 320, + "unique_traders": 85 + } + } + }, + "WsAlertEventMetricsSubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Subscribe to `event_metrics` alerts. Fired when an event's volume or transaction metrics cross a configured threshold. Use `timeframes` to restrict to specific windows (valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`).", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "subscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "event_metrics" + ] + } + }, + "example": { + "op": "subscribe", + "event": "event_metrics", + "event_slugs": [ + "example-event" + ], + "min_volume_usd": 10000.0, + "max_volume_usd": 100000.0, + "min_fees": 100.0, + "min_txns": 10, + "min_unique_traders": 10, + "timeframes": [ + "1h" + ], + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/EventMetricsFilters" + } + ] + }, + "WsAlertEventMetricsUnsubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Unsubscribe from `event_metrics` alerts. The filter fields must match the original subscription exactly.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "unsubscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "event_metrics" + ] + } + }, + "example": { + "op": "unsubscribe", + "event": "event_metrics", + "event_slugs": [ + "example-event" + ], + "min_volume_usd": 10000.0, + "max_volume_usd": 100000.0, + "min_fees": 100.0, + "min_txns": 10, + "min_unique_traders": 10, + "timeframes": [ + "1h" + ], + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/EventMetricsFilters" + } + ] + }, + "WsAlertEventMetricsEvent": { + "type": "object", + "required": [ + "event", + "timestamp", + "data" + ], + "description": "Pushed `event_metrics` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "properties": { + "event": { + "type": "string", + "enum": [ + "event_metrics" + ] + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix timestamp in milliseconds" + }, + "data": { + "$ref": "#/components/schemas/EventMetricsPayload" + } + }, + "example": { + "event": "event_metrics", + "timestamp": 1743500000000, + "data": { + "event_slug": "test-event-0000000000", + "timeframe": "1h", + "volume_usd": 120000.0, + "fees": 600.0, + "txns": 740, + "unique_traders": 210 + } + } + }, + "WsAlertPositionMetricsSubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Subscribe to `position_metrics` alerts. Fired when a position's volume or transaction metrics cross a configured threshold. Use `timeframes` to restrict to specific windows (valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`).", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "subscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "position_metrics" + ] + } + }, + "example": { + "op": "subscribe", + "event": "position_metrics", + "position_ids": [ + "452312848583266388373324160190187140051835877600158453279131187530910662656" + ], + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "outcomes": [ + "Yes" + ], + "min_volume_usd": 10000.0, + "max_volume_usd": 100000.0, + "min_buy_usd": 5000.0, + "min_sell_volume_usd": 2500.0, + "min_fees": 100.0, + "min_txns": 10, + "min_price_change_pct": 10.0, + "min_probability_change_pct": 10.0, + "timeframes": [ + "1h" + ] + } + }, + { + "$ref": "#/components/schemas/PositionMetricsFilters" + } + ] + }, + "WsAlertPositionMetricsUnsubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Unsubscribe from `position_metrics` alerts. The filter fields must match the original subscription exactly.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "unsubscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "position_metrics" + ] + } + }, + "example": { + "op": "unsubscribe", + "event": "position_metrics", + "position_ids": [ + "452312848583266388373324160190187140051835877600158453279131187530910662656" + ], + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "outcomes": [ + "Yes" + ], + "min_volume_usd": 10000.0, + "max_volume_usd": 100000.0, + "min_buy_usd": 5000.0, + "min_sell_volume_usd": 2500.0, + "min_fees": 100.0, + "min_txns": 10, + "min_price_change_pct": 10.0, + "min_probability_change_pct": 10.0, + "timeframes": [ + "1h" + ] + } + }, + { + "$ref": "#/components/schemas/PositionMetricsFilters" + } + ] + }, + "WsAlertPositionMetricsEvent": { + "type": "object", + "required": [ + "event", + "timestamp", + "data" + ], + "description": "Pushed `position_metrics` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "properties": { + "event": { + "type": "string", + "enum": [ + "position_metrics" + ] + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix timestamp in milliseconds" + }, + "data": { + "$ref": "#/components/schemas/PositionMetricsPayload" + } + }, + "example": { + "event": "position_metrics", + "timestamp": 1743500000000, + "data": { + "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", + "outcome": "Yes", + "outcome_index": 0, + "timeframe": "1h", + "volume_usd": 25000.0, + "buy_volume_usd": 15000.0, + "sell_volume_usd": 10000.0, + "fees": 125.0, + "txns": 160, + "buys": 95, + "sells": 65, + "unique_traders": 48, + "price_open": 0.48, + "price_close": 0.52, + "price_high": 0.55, + "price_low": 0.46, + "probability_open": 0.48, + "probability_close": 0.52, + "probability_high": 0.55, + "probability_low": 0.46 + } + } + }, + "WsAlertMarketVolumeMilestoneSubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Subscribe to `market_volume_milestone` alerts. Fired when a market's trading volume crosses a milestone threshold in the specified timeframe. **`timeframes` is required** (e.g. `[\"1h\", \"24h\"]`) — valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`. Optional `milestone_amounts` restricts to specific USD thresholds (e.g. `[10000, 100000]`). Optional `condition_ids` restricts to specific markets.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "subscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "market_volume_milestone" + ] + } + }, + "example": { + "op": "subscribe", + "event": "market_volume_milestone", + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "timeframes": [ + "1h" + ], + "milestone_amounts": [ + 10000 + ] + } + }, + { + "$ref": "#/components/schemas/MarketVolumeMilestoneFilters" + } + ] + }, + "WsAlertMarketVolumeMilestoneUnsubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Unsubscribe from `market_volume_milestone` alerts. The filter fields must match the original subscription exactly.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "unsubscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "market_volume_milestone" + ] + } + }, + "example": { + "op": "unsubscribe", + "event": "market_volume_milestone", + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "timeframes": [ + "1h" + ], + "milestone_amounts": [ + 10000 + ] + } + }, + { + "$ref": "#/components/schemas/MarketVolumeMilestoneFilters" + } + ] + }, + "WsAlertMarketVolumeMilestoneEvent": { + "type": "object", + "required": [ + "event", + "timestamp", + "data" + ], + "description": "Pushed `market_volume_milestone` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "properties": { + "event": { + "type": "string", + "enum": [ + "market_volume_milestone" + ] + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix timestamp in milliseconds" + }, + "data": { + "$ref": "#/components/schemas/VolumeMilestonePayload" + } + }, + "example": { + "event": "market_volume_milestone", + "timestamp": 1743500000000, + "data": { + "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + "timeframe": "24h", + "milestone_usd": 100000.0, + "current_volume_usd": 100125.0, + "fees": 500.0, + "txns": 650 + } + } + }, + "WsAlertEventVolumeMilestoneSubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Subscribe to `event_volume_milestone` alerts. Fired when an event's trading volume crosses a milestone threshold in the specified timeframe. **`timeframes` is required** (e.g. `[\"1h\", \"24h\"]`) — valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`. Optional `milestone_amounts` restricts to specific USD thresholds. Optional `event_slugs` restricts to specific events.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "subscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "event_volume_milestone" + ] + } + }, + "example": { + "op": "subscribe", + "event": "event_volume_milestone", + "event_slugs": [ + "example-event" + ], + "timeframes": [ + "1h" + ], + "milestone_amounts": [ + 10000 + ], + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/EventVolumeMilestoneFilters" + } + ] + }, + "WsAlertEventVolumeMilestoneUnsubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Unsubscribe from `event_volume_milestone` alerts. The filter fields must match the original subscription exactly.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "unsubscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "event_volume_milestone" + ] + } + }, + "example": { + "op": "unsubscribe", + "event": "event_volume_milestone", + "event_slugs": [ + "example-event" + ], + "timeframes": [ + "1h" + ], + "milestone_amounts": [ + 10000 + ], + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/EventVolumeMilestoneFilters" + } + ] + }, + "WsAlertEventVolumeMilestoneEvent": { + "type": "object", + "required": [ + "event", + "timestamp", + "data" + ], + "description": "Pushed `event_volume_milestone` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "properties": { + "event": { + "type": "string", + "enum": [ + "event_volume_milestone" + ] + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix timestamp in milliseconds" + }, + "data": { + "$ref": "#/components/schemas/EventVolumeMilestonePayload" + } + }, + "example": { + "event": "event_volume_milestone", + "timestamp": 1743500000000, + "data": { + "event_slug": "test-event-0000000000", + "timeframe": "24h", + "milestone_usd": 500000.0, + "current_volume_usd": 500250.0, + "fees": 2500.0, + "txns": 3200 + } + } + }, + "WsAlertPositionVolumeMilestoneSubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Subscribe to `position_volume_milestone` alerts. Fired when a position's trading volume crosses a milestone threshold in the specified timeframe. **`timeframes` is required** (e.g. `[\"1h\", \"24h\"]`) — valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`. Optional `milestone_amounts` restricts to specific USD thresholds. Optional `position_ids` or `condition_ids` restrict to specific positions/markets.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "subscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "position_volume_milestone" + ] + } + }, + "example": { + "op": "subscribe", + "event": "position_volume_milestone", + "position_ids": [ + "452312848583266388373324160190187140051835877600158453279131187530910662656" + ], + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "outcomes": [ + "Yes" + ], + "timeframes": [ + "1h" + ], + "milestone_amounts": [ + 10000 + ] + } + }, + { + "$ref": "#/components/schemas/PositionVolumeMilestoneFilters" + } + ] + }, + "WsAlertPositionVolumeMilestoneUnsubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Unsubscribe from `position_volume_milestone` alerts. The filter fields must match the original subscription exactly.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "unsubscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "position_volume_milestone" + ] + } + }, + "example": { + "op": "unsubscribe", + "event": "position_volume_milestone", + "position_ids": [ + "452312848583266388373324160190187140051835877600158453279131187530910662656" + ], + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "outcomes": [ + "Yes" + ], + "timeframes": [ + "1h" + ], + "milestone_amounts": [ + 10000 + ] + } + }, + { + "$ref": "#/components/schemas/PositionVolumeMilestoneFilters" + } + ] + }, + "WsAlertPositionVolumeMilestoneEvent": { + "type": "object", + "required": [ + "event", + "timestamp", + "data" + ], + "description": "Pushed `position_volume_milestone` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "properties": { + "event": { + "type": "string", + "enum": [ + "position_volume_milestone" + ] + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix timestamp in milliseconds" + }, + "data": { + "$ref": "#/components/schemas/PositionVolumeMilestonePayload" + } + }, + "example": { + "event": "position_volume_milestone", + "timestamp": 1743500000000, + "data": { + "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", + "outcome": "Yes", + "outcome_index": 0, + "timeframe": "24h", + "milestone_usd": 50000.0, + "current_volume_usd": 50125.0, + "buy_volume_usd": 30000.0, + "sell_volume_usd": 20000.0, + "fees": 250.0, + "txns": 320, + "buys": 190, + "sells": 130 + } + } + }, + "WsAlertProbabilitySpikeSubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Subscribe to `probability_spike` alerts. Fired when a position's probability moves significantly. Use `min_probability_change_pct` to set the minimum move (e.g. `10` for 10%). Use `window_secs` to observe moves within a specific time window (e.g. `60` for 60 seconds). Use `spike_direction` (`\"up\"` | `\"down\"` | `\"both\"`) — defaults to `\"up\"` when not provided. Filter by `position_ids` or `outcomes` to narrow scope.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "subscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "probability_spike" + ] + } + }, + "example": { + "op": "subscribe", + "event": "probability_spike", + "position_ids": [ + "452312848583266388373324160190187140051835877600158453279131187530910662656" + ], + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "event_slugs": [ + "example-event" + ], + "outcomes": [ + "Yes" + ], + "min_probability_change_pct": 10.0, + "spike_direction": "up", + "window_secs": 60, + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/ProbabilitySpikeFilters" + } + ] + }, + "WsAlertProbabilitySpikeUnsubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Unsubscribe from `probability_spike` alerts. The filter fields must match the original subscription exactly.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "unsubscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "probability_spike" + ] + } + }, + "example": { + "op": "unsubscribe", + "event": "probability_spike", + "position_ids": [ + "452312848583266388373324160190187140051835877600158453279131187530910662656" + ], + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "event_slugs": [ + "example-event" + ], + "outcomes": [ + "Yes" + ], + "min_probability_change_pct": 10.0, + "spike_direction": "up", + "window_secs": 60, + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/ProbabilitySpikeFilters" + } + ] + }, + "WsAlertProbabilitySpikeEvent": { + "type": "object", + "required": [ + "event", + "timestamp", + "data" + ], + "description": "Pushed `probability_spike` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "properties": { + "event": { + "type": "string", + "enum": [ + "probability_spike" + ] + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix timestamp in milliseconds" + }, + "data": { + "$ref": "#/components/schemas/ProbabilitySpikePayload" + } + }, + "example": { + "event": "probability_spike", + "timestamp": 1743500000000, + "data": { + "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", + "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + "event_slug": "test-event-0000000000", + "outcome": "Yes", + "outcome_index": 0, + "previous_probability": 0.4, + "current_probability": 0.5, + "spike_direction": "up", + "spike_pct": 25.0 + } + } + }, + "WsAlertPriceSpikeSubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Subscribe to `price_spike` alerts. Fired when a position's price moves significantly. Use `min_price_change_pct` to set the minimum move (e.g. `10` for 10%). Use `window_secs` to observe moves within a specific time window. Use `spike_direction` (`\"up\"` | `\"down\"` | `\"both\"`) — defaults to `\"up\"` when not provided. Filter by `position_ids` or `outcomes` to narrow scope.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "subscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "price_spike" + ] + } + }, + "example": { + "op": "subscribe", + "event": "price_spike", + "position_ids": [ + "452312848583266388373324160190187140051835877600158453279131187530910662656" + ], + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "event_slugs": [ + "example-event" + ], + "outcomes": [ + "Yes" + ], + "min_price_change_pct": 10.0, + "spike_direction": "up", + "window_secs": 60, + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/PriceSpikeFilters" + } + ] + }, + "WsAlertPriceSpikeUnsubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Unsubscribe from `price_spike` alerts. The filter fields must match the original subscription exactly.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "unsubscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "price_spike" + ] + } + }, + "example": { + "op": "unsubscribe", + "event": "price_spike", + "position_ids": [ + "452312848583266388373324160190187140051835877600158453279131187530910662656" + ], + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "event_slugs": [ + "example-event" + ], + "outcomes": [ + "Yes" + ], + "min_price_change_pct": 10.0, + "spike_direction": "up", + "window_secs": 60, + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/PriceSpikeFilters" + } + ] + }, + "WsAlertPriceSpikeEvent": { + "type": "object", + "required": [ + "event", + "timestamp", + "data" + ], + "description": "Pushed `price_spike` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "properties": { + "event": { + "type": "string", + "enum": [ + "price_spike" + ] + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix timestamp in milliseconds" + }, + "data": { + "$ref": "#/components/schemas/PriceSpikePayload" + } + }, + "example": { + "event": "price_spike", + "timestamp": 1743500000000, + "data": { + "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", + "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + "event_slug": "test-event-0000000000", + "outcome": "Yes", + "outcome_index": 0, + "previous_price": 0.4, + "current_price": 0.5, + "spike_direction": "up", + "spike_pct": 25.0 + } + } + }, + "WsAlertMarketVolumeSpikeSubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Subscribe to `market_volume_spike` alerts. Fired when a market's trading volume grows by a multiple of `spike_ratio` within a timeframe. Requires `spike_ratio` (> 1.0, e.g. `2.0` fires when volume doubles). Optional `window_secs` sets the observation window in seconds (max 600). Optional `timeframes` — valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `1d`, `24h`, `7d`, `30d`. Optional `condition_ids` restricts to specific markets.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "subscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "market_volume_spike" + ] + } + }, + "example": { + "op": "subscribe", + "event": "market_volume_spike", + "spike_ratio": 2.0, + "window_secs": 60, + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "timeframes": [ + "1h" + ] + } + }, + { + "$ref": "#/components/schemas/MarketVolumeSpikeFilters" + } + ] + }, + "WsAlertMarketVolumeSpikeUnsubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Unsubscribe from `market_volume_spike` alerts. The filter fields must match the original subscription exactly.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "unsubscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "market_volume_spike" + ] + } + }, + "example": { + "op": "unsubscribe", + "event": "market_volume_spike", + "spike_ratio": 2.0, + "window_secs": 60, + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "timeframes": [ + "1h" + ] + } + }, + { + "$ref": "#/components/schemas/MarketVolumeSpikeFilters" + } + ] + }, + "WsAlertMarketVolumeSpikeEvent": { + "type": "object", + "required": [ + "event", + "timestamp", + "data" + ], + "description": "Pushed `market_volume_spike` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "properties": { + "event": { + "type": "string", + "enum": [ + "market_volume_spike" + ] + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix timestamp in milliseconds" + }, + "data": { + "$ref": "#/components/schemas/MarketVolumeSpikePayload" + } + }, + "example": { + "event": "market_volume_spike", + "timestamp": 1743500000000, + "data": { + "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + "timeframe": "1h", + "current_volume_usd": 32000.0, + "snapshot_volume_usd": 10000.0, + "delta_volume_usd": 22000.0, + "spike_pct": 220.0, + "txns": 480, + "fees": 160.0 + } + } + }, + "WsAlertEventVolumeSpikeSubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Subscribe to `event_volume_spike` alerts. Fired when an event's aggregated trading volume grows by a multiple of `spike_ratio` within a timeframe. Requires `spike_ratio` (> 1.0, e.g. `2.0` fires when volume doubles). Optional `window_secs` sets the observation window in seconds (max 600). Optional `timeframes` and `event_slugs` to narrow scope.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "subscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "event_volume_spike" + ] + } + }, + "example": { + "op": "subscribe", + "event": "event_volume_spike", + "spike_ratio": 2.0, + "window_secs": 60, + "event_slugs": [ + "example-event" + ], + "timeframes": [ + "1h" + ], + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/EventVolumeSpikeFilters" + } + ] + }, + "WsAlertEventVolumeSpikeUnsubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Unsubscribe from `event_volume_spike` alerts. The filter fields must match the original subscription exactly.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "unsubscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "event_volume_spike" + ] + } + }, + "example": { + "op": "unsubscribe", + "event": "event_volume_spike", + "spike_ratio": 2.0, + "window_secs": 60, + "event_slugs": [ + "example-event" + ], + "timeframes": [ + "1h" + ], + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/EventVolumeSpikeFilters" + } + ] + }, + "WsAlertEventVolumeSpikeEvent": { + "type": "object", + "required": [ + "event", + "timestamp", + "data" + ], + "description": "Pushed `event_volume_spike` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "properties": { + "event": { + "type": "string", + "enum": [ + "event_volume_spike" + ] + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix timestamp in milliseconds" + }, + "data": { + "$ref": "#/components/schemas/EventVolumeSpikePayload" + } + }, + "example": { + "event": "event_volume_spike", + "timestamp": 1743500000000, + "data": { + "event_slug": "test-event-0000000000", + "timeframe": "1h", + "current_volume_usd": 140000.0, + "snapshot_volume_usd": 50000.0, + "delta_volume_usd": 90000.0, + "spike_pct": 180.0, + "txns": 1100, + "fees": 700.0 + } + } + }, + "WsAlertPositionVolumeSpikeSubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Subscribe to `position_volume_spike` alerts. Fired when a position's trading volume grows by a multiple of `spike_ratio` within a timeframe. Requires `spike_ratio` (> 1.0, e.g. `2.0` fires when volume doubles). Optional `window_secs` sets the observation window in seconds (max 600). Optional `position_ids`, `condition_ids`, `outcomes`, and `timeframes` to narrow scope.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "subscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "position_volume_spike" + ] + } + }, + "example": { + "op": "subscribe", + "event": "position_volume_spike", + "spike_ratio": 2.0, + "window_secs": 60, + "position_ids": [ + "452312848583266388373324160190187140051835877600158453279131187530910662656" + ], + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "outcomes": [ + "Yes" + ], + "timeframes": [ + "1h" + ] + } + }, + { + "$ref": "#/components/schemas/PositionVolumeSpikeFilters" + } + ] + }, + "WsAlertPositionVolumeSpikeUnsubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Unsubscribe from `position_volume_spike` alerts. The filter fields must match the original subscription exactly.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "unsubscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "position_volume_spike" + ] + } + }, + "example": { + "op": "unsubscribe", + "event": "position_volume_spike", + "spike_ratio": 2.0, + "window_secs": 60, + "position_ids": [ + "452312848583266388373324160190187140051835877600158453279131187530910662656" + ], + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "outcomes": [ + "Yes" + ], + "timeframes": [ + "1h" + ] + } + }, + { + "$ref": "#/components/schemas/PositionVolumeSpikeFilters" + } + ] + }, + "WsAlertPositionVolumeSpikeEvent": { + "type": "object", + "required": [ + "event", + "timestamp", + "data" + ], + "description": "Pushed `position_volume_spike` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "properties": { + "event": { + "type": "string", + "enum": [ + "position_volume_spike" + ] + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix timestamp in milliseconds" + }, + "data": { + "$ref": "#/components/schemas/PositionVolumeSpikePayload" + } + }, + "example": { + "event": "position_volume_spike", + "timestamp": 1743500000000, + "data": { + "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", + "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + "outcome": "Yes", + "outcome_index": 0, + "timeframe": "1h", + "current_volume_usd": 20500.0, + "snapshot_volume_usd": 5000.0, + "delta_volume_usd": 15500.0, + "spike_pct": 310.0, + "txns": 240, + "fees": 102.5 + } + } + }, + "WsAlertCloseToBondSubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Subscribe to `close_to_bond` alerts. Fired when a trade occurs at a near-certain-outcome price. **At least one of `min_probability` or `max_probability` is required.** Use `min_probability` (e.g. `0.95`) to trigger when YES is near-certain; use `max_probability` (e.g. `0.05`) for NO near-certain. Optional filters: `position_outcome_indices` — restrict by outcome index (`0` = Yes/Up, `1` = No); `condition_ids` — restrict to specific markets; `position_ids` — restrict to specific outcome tokens; `outcomes` — restrict by outcome name (e.g. `\"Yes\"`, `\"No\"`); `event_slugs` — restrict to specific events.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "subscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "close_to_bond" + ] + } + }, + "example": { + "op": "subscribe", + "event": "close_to_bond", + "min_probability": 0.95, + "max_probability": 0.05, + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "position_ids": [ + "452312848583266388373324160190187140051835877600158453279131187530910662656" + ], + "outcomes": [ + "Yes" + ], + "position_outcome_indices": [ + 0 + ], + "event_slugs": [ + "example-event" + ], + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/CloseToBondFilters" + } + ], + "anyOf": [ + { + "required": [ + "min_probability" + ] + }, + { + "required": [ + "max_probability" + ] + } + ] + }, + "WsAlertCloseToBondUnsubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Unsubscribe from `close_to_bond` alerts. The filter fields must match the original subscription exactly.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "unsubscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "close_to_bond" + ] + } + }, + "example": { + "op": "unsubscribe", + "event": "close_to_bond", + "min_probability": 0.95, + "max_probability": 0.05, + "condition_ids": [ + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "position_ids": [ + "452312848583266388373324160190187140051835877600158453279131187530910662656" + ], + "outcomes": [ + "Yes" + ], + "position_outcome_indices": [ + 0 + ], + "event_slugs": [ + "example-event" + ], + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/CloseToBondFilters" + } + ], + "anyOf": [ + { + "required": [ + "min_probability" + ] + }, + { + "required": [ + "max_probability" + ] + } + ] + }, + "WsAlertCloseToBondEvent": { + "type": "object", + "required": [ + "event", + "timestamp", + "data" + ], + "description": "Pushed `close_to_bond` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "properties": { + "event": { + "type": "string", + "enum": [ + "close_to_bond" + ] + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix timestamp in milliseconds" + }, + "data": { + "$ref": "#/components/schemas/CloseToBondPayload" + } + }, + "example": { + "event": "close_to_bond", + "timestamp": 1743500000000, + "data": { + "trader": "0x0000000000000000000000000000000000000000", + "taker": "0x0000000000000000000000000000000000000000", + "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", + "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + "outcome": "Yes", + "outcome_index": 0, + "question": "Will this test webhook fire correctly?", + "market_slug": "test-market-0000000000", + "event_slug": "test-event-0000000000", + "trade_id": "00000000-0000-0000-0000-000000000000", + "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "block": 0, + "confirmed_at": 1700000000, + "amount_usd": 500.0, + "shares_amount": 515.46, + "fee": 2.5, + "side": "Buy", + "price": 0.97, + "probability": 0.97, + "bond_side": "high", + "threshold": 0.95 + } + } + }, + "WsAlertMarketCreatedSubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Subscribe to `market_created` alerts. Fired when a new prediction market is created on Polymarket. Filterable by `tags` and `event_slugs`.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "subscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "market_created" + ] + } + }, + "example": { + "op": "subscribe", + "event": "market_created", + "event_slugs": [ + "example-event" + ], + "tags": [ + "Politics" + ], + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/MarketCreatedFilters" + } + ] + }, + "WsAlertMarketCreatedUnsubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Unsubscribe from `market_created` alerts. The filter fields must match the original subscription exactly.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "unsubscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "market_created" + ] + } + }, + "example": { + "op": "unsubscribe", + "event": "market_created", + "event_slugs": [ + "example-event" + ], + "tags": [ + "Politics" + ], + "exclude_shortterm_markets": true + } + }, + { + "$ref": "#/components/schemas/MarketCreatedFilters" + } + ] + }, + "WsAlertMarketCreatedEvent": { + "type": "object", + "required": [ + "event", + "timestamp", + "data" + ], + "description": "Pushed `market_created` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "properties": { + "event": { + "type": "string", + "enum": [ + "market_created" + ] + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix timestamp in milliseconds" + }, + "data": { + "$ref": "#/components/schemas/MarketCreatedPayload" + } + }, + "example": { + "event": "market_created", + "timestamp": 1743500000000, + "data": { + "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + "market_slug": "test-market-0000000000", + "event_slug": "test-event-0000000000", + "event_id": null, + "event_title": "Test Event 0000", + "series_slug": null, + "outcomes": [ + { + "index": 0, + "name": "Yes", + "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656" + }, + { + "index": 1, + "name": "No", + "position_id": "0" + } + ], + "question": "Will this test webhook fire correctly?", + "title": "Test Market 0000", + "description": "A test market for webhook payload verification.", + "category": "Crypto", + "tags": [ + "test", + "crypto" + ], + "image_url": null, + "neg_risk": false + } + } + }, + "WsAlertAssetPriceTickSubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Subscribe to `asset_price_tick` alerts. Fired when the price of a tracked crypto asset updates (BTC, ETH, SOL, XRP, DOGE, BNB, HYPE). Use `asset_symbols` to restrict to specific assets (empty = all).", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "subscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "asset_price_tick" + ] + } + }, + "example": { + "op": "subscribe", + "event": "asset_price_tick", + "asset_symbols": [ + "BTC" + ] + } + }, + { + "$ref": "#/components/schemas/AssetPriceTickFilters" + } + ] + }, + "WsAlertAssetPriceTickUnsubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Unsubscribe from `asset_price_tick` alerts. The filter fields must match the original subscription exactly.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "unsubscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "asset_price_tick" + ] + } + }, + "example": { + "op": "unsubscribe", + "event": "asset_price_tick", + "asset_symbols": [ + "BTC" + ] + } + }, + { + "$ref": "#/components/schemas/AssetPriceTickFilters" + } + ] + }, + "WsAlertAssetPriceTickEvent": { + "type": "object", + "required": [ + "event", + "timestamp", + "data" + ], + "description": "Pushed `asset_price_tick` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "properties": { + "event": { + "type": "string", + "enum": [ + "asset_price_tick" + ] + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix timestamp in milliseconds" + }, + "data": { + "$ref": "#/components/schemas/AssetPriceTickPayload" + } + }, + "example": { + "event": "asset_price_tick", + "timestamp": 1743500000000, + "data": { + "symbol": "BTC", + "price": 65000.0, + "timestamp_ms": 1700000000000 + } + } + }, + "WsAlertAssetPriceWindowUpdateSubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Subscribe to `asset_price_window_update` alerts. Fired at the start and end of each price candle for tracked crypto assets (BTC, ETH, SOL, XRP, DOGE, BNB, HYPE). Payload includes `update_type` (`\"open\"` or `\"close\"`) indicating whether the candle is opening or closing. Use `asset_symbols` to restrict to specific assets. Use `timeframes` to restrict to specific candle sizes — valid values: `\"5m\"`, `\"15m\"`, `\"1h\"`, `\"4h\"`, `\"1d\"`, `\"24h\"`.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "subscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "asset_price_window_update" + ] + } + }, + "example": { + "op": "subscribe", + "event": "asset_price_window_update", + "asset_symbols": [ + "BTC" + ], + "timeframes": [ + "1h" + ] + } + }, + { + "$ref": "#/components/schemas/AssetPriceWindowUpdateFilters" + } + ] + }, + "WsAlertAssetPriceWindowUpdateUnsubscribeMessage": { + "allOf": [ + { + "type": "object", + "description": "Unsubscribe from `asset_price_window_update` alerts. The filter fields must match the original subscription exactly.", + "required": [ + "op", + "event" + ], + "properties": { + "op": { + "type": "string", + "enum": [ + "unsubscribe" + ] + }, + "event": { + "type": "string", + "enum": [ + "asset_price_window_update" + ] + } + }, + "example": { + "op": "unsubscribe", + "event": "asset_price_window_update", + "asset_symbols": [ + "BTC" + ], + "timeframes": [ + "1h" + ] + } + }, + { + "$ref": "#/components/schemas/AssetPriceWindowUpdateFilters" + } + ] + }, + "WsAlertAssetPriceWindowUpdateEvent": { + "type": "object", + "required": [ + "event", + "timestamp", + "data" + ], + "description": "Pushed `asset_price_window_update` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", + "properties": { + "event": { + "type": "string", + "enum": [ + "asset_price_window_update" + ] + }, + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix timestamp in milliseconds" + }, + "data": { + "$ref": "#/components/schemas/AssetPriceWindowUpdatePayload" + } + }, + "example": { + "event": "asset_price_window_update", + "timestamp": 1743500000000, + "data": { + "symbol": "BTC", + "variant": "1h", + "start_time": 1700000000000, + "end_time": 1700003600000, + "open_price": 64800.0, + "close_price": 65200.0, + "update_type": "close" + } + } + }, + "WsAlertSubscribeMessage": { + "description": "Typed subscribe request for the alerts WebSocket. The request shape depends on `event` and reuses the matching webhook filter schema.", + "oneOf": [ + { + "$ref": "#/components/schemas/WsAlertTraderFirstTradeSubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertTraderNewMarketSubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertTraderWhaleTradeSubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertTraderNewTradeSubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertTraderGlobalPnlSubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertTraderMarketPnlSubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertTraderEventPnlSubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertConditionMetricsSubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertEventMetricsSubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertPositionMetricsSubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertMarketVolumeMilestoneSubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertEventVolumeMilestoneSubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertPositionVolumeMilestoneSubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertProbabilitySpikeSubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertPriceSpikeSubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertMarketVolumeSpikeSubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertEventVolumeSpikeSubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertPositionVolumeSpikeSubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertCloseToBondSubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertMarketCreatedSubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertAssetPriceTickSubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertAssetPriceWindowUpdateSubscribeMessage" + } + ], + "discriminator": "event" + }, + "WsAlertUnsubscribeMessage": { + "description": "Typed unsubscribe request for the alerts WebSocket. The request shape depends on `event` and must match the original subscription filters.", + "oneOf": [ + { + "$ref": "#/components/schemas/WsAlertTraderFirstTradeUnsubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertTraderNewMarketUnsubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertTraderWhaleTradeUnsubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertTraderNewTradeUnsubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertTraderGlobalPnlUnsubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertTraderMarketPnlUnsubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertTraderEventPnlUnsubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertConditionMetricsUnsubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertEventMetricsUnsubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertPositionMetricsUnsubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertMarketVolumeMilestoneUnsubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertEventVolumeMilestoneUnsubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertPositionVolumeMilestoneUnsubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertProbabilitySpikeUnsubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertPriceSpikeUnsubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertMarketVolumeSpikeUnsubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertEventVolumeSpikeUnsubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertPositionVolumeSpikeUnsubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertCloseToBondUnsubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertMarketCreatedUnsubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertAssetPriceTickUnsubscribeMessage" + }, + { + "$ref": "#/components/schemas/WsAlertAssetPriceWindowUpdateUnsubscribeMessage" + } + ], + "discriminator": "event" + }, + "WsAlertEventPayload": { + "description": "Typed pushed-event envelope for the alerts WebSocket. The `data` payload depends on `event` and matches the corresponding HTTP webhook payload schema.", + "oneOf": [ + { + "$ref": "#/components/schemas/WsAlertTraderFirstTradeEvent" + }, + { + "$ref": "#/components/schemas/WsAlertTraderNewMarketEvent" + }, + { + "$ref": "#/components/schemas/WsAlertTraderWhaleTradeEvent" + }, + { + "$ref": "#/components/schemas/WsAlertTraderNewTradeEvent" + }, + { + "$ref": "#/components/schemas/WsAlertTraderGlobalPnlEvent" + }, + { + "$ref": "#/components/schemas/WsAlertTraderMarketPnlEvent" + }, + { + "$ref": "#/components/schemas/WsAlertTraderEventPnlEvent" + }, + { + "$ref": "#/components/schemas/WsAlertConditionMetricsEvent" + }, + { + "$ref": "#/components/schemas/WsAlertEventMetricsEvent" + }, + { + "$ref": "#/components/schemas/WsAlertPositionMetricsEvent" + }, + { + "$ref": "#/components/schemas/WsAlertMarketVolumeMilestoneEvent" + }, + { + "$ref": "#/components/schemas/WsAlertEventVolumeMilestoneEvent" + }, + { + "$ref": "#/components/schemas/WsAlertPositionVolumeMilestoneEvent" + }, + { + "$ref": "#/components/schemas/WsAlertProbabilitySpikeEvent" + }, + { + "$ref": "#/components/schemas/WsAlertPriceSpikeEvent" + }, + { + "$ref": "#/components/schemas/WsAlertMarketVolumeSpikeEvent" + }, + { + "$ref": "#/components/schemas/WsAlertEventVolumeSpikeEvent" + }, + { + "$ref": "#/components/schemas/WsAlertPositionVolumeSpikeEvent" + }, + { + "$ref": "#/components/schemas/WsAlertCloseToBondEvent" + }, + { + "$ref": "#/components/schemas/WsAlertMarketCreatedEvent" + }, + { + "$ref": "#/components/schemas/WsAlertAssetPriceTickEvent" + }, + { + "$ref": "#/components/schemas/WsAlertAssetPriceWindowUpdateEvent" + } + ], + "discriminator": "event" + } + }, + "securitySchemes": { + "apiKeyHeader": { + "type": "httpApiKey", + "in": "header", + "name": "X-Api-Key", + "description": "Pass the API key via the `X-Api-Key` header on the WebSocket upgrade request." + }, + "apiKeyQuery": { + "type": "httpApiKey", + "in": "query", + "name": "api-key", + "description": "Pass the API key via `?api-key=` on the WebSocket upgrade URL (browser/frontend friendly)." + }, + "publicKeyJwt": { + "type": "http", + "scheme": "bearer", + "bearerFormat": "JWT", + "description": "Public-key JWT combo: the builder embeds a `pk_jwt_*` key in their frontend, and end users supply a JWT signed by the builder. Send via `Authorization: Bearer ` header or `?token=` query parameter. Credits bill to the builder's org; rate limits are applied per session." + } + } + } +} \ No newline at end of file diff --git a/openapi/ws.json b/openapi/ws.json index a5bf4fa..e79dce6 100644 --- a/openapi/ws.json +++ b/openapi/ws.json @@ -1,9 +1,9 @@ { "asyncapi": "3.0.0", "info": { - "title": "Polymarket WebSocket API", + "title": "Polymarket WebSocket Streams API", "version": "1.0.0", - "description": "Real-time WebSocket streaming API for Polymarket prediction-market data.\n\n## Connection\nConnect to `wss://api.struct.to/ws` using a standard WebSocket client.\n\n## Authentication\nAn API key is required. Pass it via **header** or **query parameter**:\n\n**Header (recommended):**\n```\nX-Api-Key: \n```\n\n**Query parameter (browser / frontend):**\n```\nwss://api.struct.to/ws?api_key=\n```\n\nThe query parameter is only used when no `X-Api-Key` header is present.\n\n## Joining a room\nAfter connecting, send:\n```json\n{\"type\":\"join_room\",\"payload\":{\"room_id\":\"polymarket_trades\"}}\n```\n\n## Subscribing\nAfter joining, send a `room_message` with room-specific subscribe payload:\n```json\n{\n\"type\": \"room_message\",\n\"payload\": {\n\"room_id\": \"polymarket_trades\",\n\"message\": {\"action\":\"subscribe\",\"condition_ids\":[\"0xabc…\"]}\n}\n}\n```\n\n## Keepalive\nSend `{\"type\":\"ping\"}` periodically to keep your connection alive. The server responds with `{\"type\":\"pong\"}`. Connections that have not sent a `ping` within **60 seconds** are closed." + "description": "Real-time WebSocket streaming API for Polymarket prediction-market data.\n\n## Connection\nConnect to `wss://api.struct.to/ws` using a standard WebSocket client.\n\n## Authentication\n\nTwo authentication methods are supported:\n\n**1. API key** (`apiKeyHeader` or `apiKeyQuery`):\n```\nX-Api-Key: \n```\nor\n```\nwss://api.struct.to/ws?api_key=\n```\n\n**2. Public-key JWT combo** (`publicKeyJwt`): for builders who embed a `pk_jwt_*` key in their frontend and issue JWTs to their end users. Credits bill to the builder's org; rate limits are per session.\n```\nAuthorization: Bearer \n```\nor\n```\nwss://api.struct.to/ws?token=\n```\n\n## Joining a room\nAfter connecting, send:\n```json\n{\"type\":\"join_room\",\"payload\":{\"room_id\":\"polymarket_trades\"}}\n```\n\n## Subscribing\nAfter joining, send a `room_message` with room-specific subscribe payload:\n```json\n{\n\"type\": \"room_message\",\n\"payload\": {\n\"room_id\": \"polymarket_trades\",\n\"message\": {\"action\":\"subscribe\",\"condition_ids\":[\"0xabc…\"]}\n}\n}\n```\n\n## Keepalive\nSend `{\"type\":\"ping\"}` periodically to keep your connection alive. The server responds with `{\"type\":\"pong\"}`. Connections that have not sent a `ping` within **60 seconds** are closed. Recommended: send a ping every 30 seconds.\n\n## Pricing\nWebSocket billing is **per message**, with costs varying by room type. The credit system is integer-based, so fractional costs accumulate per connection and are only deducted when a whole credit is reached. Any fractional remainder is **rounded up to the next credit** when the connection closes.\n\n**Connection hold:** Every new authenticated connection is charged a **1-credit hold** immediately on connect, even if the client disconnects before receiving any messages.\n\n**Per-message cost by room:**\n\n| Room | Credits per message |\n|---|---|\n| `polymarket_trades` (Trades) | 0.025 |\n| `polymarket_order_book` (Order Book) | 0.01 |\n| `polymarket_asset_prices` (Asset Prices) | 0.05 |\n| `polymarket_asset_window_updates` (Asset Window Updates) | 0.25 |\n| `polymarket_market_metrics` (Market Metrics) | 0.25 |\n| `polymarket_event_metrics` (Event Metrics) | 0.25 |\n| `polymarket_position_metrics` (Position Metrics) | 0.25 |\n| `polymarket_trader_pnl` (Trader PnL) | 1 |\n| `polymarket_trader_positions` (Trader Positions) | 0.05 |\n| `polymarket_accounts` (Accounts) | 0.05 |\n| `polymarket_clob_rewards` (CLOB Rewards) | 0.1 |\n\nSystem messages (`pong`, `room_joined`, `room_left`, errors) are free." }, "servers": { "production": { @@ -11,12 +11,6 @@ "pathname": "/ws", "protocol": "wss", "description": "Production WebSocket endpoint (room-based subscriptions)" - }, - "alerts": { - "host": "api.struct.to", - "pathname": "/v1/ws/alerts", - "protocol": "wss", - "description": "WebSocket alerts endpoint — ephemeral real-time alert subscriptions. Pass API key via ?api-key= query parameter. Subscribe/unsubscribe by sending JSON messages. Subscriptions are ephemeral and end on disconnect." } }, "channels": { @@ -221,37 +215,6 @@ "$ref": "#/components/messages/ClobRewardsUpdateEvent" } } - }, - "ws_alerts": { - "address": "/v1/ws/alerts", - "title": "WebSocket Alerts", - "summary": "Ephemeral real-time alert subscriptions over WebSocket", - "description": "Connect to `wss://api.struct.to/v1/ws/alerts?api-key=`. Subscribe to webhook-style alert events by sending JSON messages. Subscriptions are ephemeral and end when the connection closes. The alerts WS path shares the same event/filter pipeline as HTTP webhooks; only delivery transport differs. Credits cost matches the corresponding webhook event.\n\n**Supported events:** trader_first_trade, trader_new_market, trader_whale_trade, trader_new_trade, trader_global_pnl, trader_market_pnl, trader_event_pnl, condition_metrics, event_metrics, position_metrics, market_volume_milestone, event_volume_milestone, position_volume_milestone, probability_spike, price_spike, market_volume_spike, event_volume_spike, position_volume_spike, close_to_bond, market_created, asset_price_tick, asset_price_window_update\n\nEach subscribe/unsubscribe request is typed per event and reuses the matching webhook filter schema. Server acknowledgements use `{\"op\":\"subscribed\"|\"unsubscribed\", ...}`, and pushed alert events use `{\"event\":\"...\",\"timestamp\":...,\"data\": ...}`.", - "servers": [ - { - "$ref": "#/servers/alerts" - } - ], - "messages": { - "subscribe": { - "$ref": "#/components/messages/WsAlertSubscribe" - }, - "unsubscribe": { - "$ref": "#/components/messages/WsAlertUnsubscribe" - }, - "subscribed": { - "$ref": "#/components/messages/WsAlertSubscribed" - }, - "unsubscribed": { - "$ref": "#/components/messages/WsAlertUnsubscribed" - }, - "error": { - "$ref": "#/components/messages/WsAlertError" - }, - "alertEvent": { - "$ref": "#/components/messages/WsAlertEvent" - } - } } }, "operations": { @@ -566,42 +529,6 @@ "$ref": "#/channels/polymarket_clob_rewards/messages/clobRewardsUpdateEvent" } ] - }, - "subscribeWsAlerts": { - "action": "send", - "channel": { - "$ref": "#/channels/ws_alerts" - }, - "summary": "Subscribe or unsubscribe to alert events", - "messages": [ - { - "$ref": "#/channels/ws_alerts/messages/subscribe" - }, - { - "$ref": "#/channels/ws_alerts/messages/unsubscribe" - } - ] - }, - "receiveWsAlerts": { - "action": "receive", - "channel": { - "$ref": "#/channels/ws_alerts" - }, - "summary": "Receive typed alert events and subscription acknowledgements", - "messages": [ - { - "$ref": "#/channels/ws_alerts/messages/subscribed" - }, - { - "$ref": "#/channels/ws_alerts/messages/unsubscribed" - }, - { - "$ref": "#/channels/ws_alerts/messages/error" - }, - { - "$ref": "#/channels/ws_alerts/messages/alertEvent" - } - ] } }, "components": { @@ -833,279 +760,280 @@ "payload": { "$ref": "#/components/schemas/ClobRewardsSubscribeResponse" } - }, - "WsAlertSubscribe": { - "summary": "Subscribe to an alert event type", - "payload": { - "$ref": "#/components/schemas/WsAlertSubscribeMessage" - } - }, - "WsAlertUnsubscribe": { - "summary": "Unsubscribe from an alert event type", - "payload": { - "$ref": "#/components/schemas/WsAlertUnsubscribeMessage" - } - }, - "WsAlertSubscribed": { - "summary": "Alert subscription acknowledgement", - "payload": { - "$ref": "#/components/schemas/WsAlertSubscribedResponse" - } - }, - "WsAlertUnsubscribed": { - "summary": "Alert unsubscription acknowledgement", - "payload": { - "$ref": "#/components/schemas/WsAlertUnsubscribedResponse" - } - }, - "WsAlertError": { - "summary": "Alerts WebSocket error response", - "payload": { - "$ref": "#/components/schemas/WsAlertErrorResponse" - } - }, - "WsAlertEvent": { - "summary": "Typed alert event pushed from server", - "payload": { - "$ref": "#/components/schemas/WsAlertEventPayload" - } } }, "schemas": { - "AssetPriceWindowUpdateFilters": { + "ClobRewardsUpdateEvent": { "type": "object", - "description": "Subscription filters for the `asset_price_window_update` event. All fields are optional.", + "description": "Server-pushed CLOB reward change event. Envelope type: \"clob_rewards_update\".", "properties": { - "asset_symbols": { - "type": "array", - "items": { - "type": "string", - "enum": [ - "BTC", - "ETH", - "SOL", - "XRP", - "DOGE", - "BNB", - "HYPE" - ] - }, - "maxItems": 500, - "description": "Restrict to these crypto assets. Empty = all assets." + "event_type": { + "type": "string", + "enum": [ + "added", + "removed", + "updated" + ], + "description": "Type of change" }, - "timeframes": { - "type": "array", - "items": { - "type": "string", - "enum": [ - "5m", - "15m", - "1h", - "4h", - "1d", - "24h" - ] - }, - "maxItems": 500, - "description": "Restrict to these candle sizes. Empty = all sizes." - } - } - }, - "AssetPriceTickFilters": { - "type": "object", - "description": "Subscription filters for the `asset_price_tick` event. All fields are optional.", - "properties": { - "asset_symbols": { - "type": "array", - "items": { - "type": "string", - "enum": [ - "BTC", - "ETH", - "SOL", - "XRP", - "DOGE", - "BNB", - "HYPE" - ] - }, - "description": "Restrict to these crypto assets. Empty = all assets." + "condition_id": { + "type": "string", + "description": "Affected market condition ID" + }, + "reward": { + "type": [ + "object", + "null" + ], + "description": "Full reward state (null for 'removed' events)", + "properties": { + "condition_id": { + "type": "string" + }, + "rewards_config": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "asset_address": { + "type": "string", + "description": "Reward token address (e.g. USDC)" + }, + "start_date": { + "type": "string", + "format": "date" + }, + "end_date": { + "type": "string", + "format": "date" + }, + "rate_per_day": { + "type": "number", + "description": "Daily reward rate in USDC" + }, + "total_rewards": { + "type": "number", + "description": "Cumulative rewards distributed" + } + } + } + }, + "rewards_max_spread": { + "type": [ + "number", + "null" + ], + "description": "Max spread to qualify for rewards" + }, + "rewards_min_size": { + "type": [ + "number", + "null" + ], + "description": "Min order size to qualify for rewards" + }, + "native_daily_rate": { + "type": [ + "number", + "null" + ], + "description": "Native (non-sponsored) daily rate" + }, + "sponsored_daily_rate": { + "type": [ + "number", + "null" + ], + "description": "Sponsored daily rate" + }, + "total_daily_rate": { + "type": [ + "number", + "null" + ], + "description": "Combined daily rate (native + sponsored)" + }, + "sponsors_count": { + "type": [ + "integer", + "null" + ], + "description": "Number of sponsors" + } + } + }, + "timestamp_ms": { + "type": "integer", + "description": "Unix timestamp in milliseconds" } } }, - "MarketCreatedFilters": { + "ClobRewardsSubscribeResponse": { "type": "object", - "description": "Subscription filters for the `market_created` event. All fields are optional.", + "description": "Server acknowledgement for a CLOB rewards subscription. Envelope type: \"clob_rewards_stream_subscribe_response\".", "properties": { - "tags": { - "type": "array", - "items": { - "type": "string" - }, - "maxItems": 500, - "description": "Restrict to markets with these tags or category names (case-insensitive match)." - }, "condition_ids": { "type": "array", "items": { "type": "string" }, - "maxItems": 500, - "description": "Restrict to these specific markets." + "description": "Accepted condition IDs" }, - "event_slugs": { + "subscribe_all": { + "type": "boolean", + "description": "Whether subscribed to all changes" + }, + "rejected": { "type": "array", "items": { "type": "string" }, - "maxItems": 500, - "description": "Restrict to markets belonging to these events." - }, - "exclude_shortterm_markets": { - "type": "boolean", - "description": "When `true`, suppress webhooks for short-term \"updown\" markets (event slugs containing `updown`). Default: `false`." + "description": "Filter values that were rejected" } } }, - "CloseToBondFilters": { + "ClobRewardsSubscribeMessage": { "type": "object", - "description": "Subscription filters for the `close_to_bond` event. At least one of `min_probability` or `max_probability` is required.", - "anyOf": [ - { - "required": [ - "min_probability" - ] - }, - { - "required": [ - "max_probability" - ] - } + "description": "Subscribe to CLOB reward changes. Either provide specific condition_ids or set subscribe_all to true.", + "required": [ + "action" ], "properties": { - "min_probability": { - "type": "number", - "minimum": 0.0, - "maximum": 1.0, - "description": "Trigger when the YES outcome price is ≥ this value (e.g. 0.95 for 95% certainty). At least one of `min_probability` or `max_probability` must be set." - }, - "max_probability": { - "type": "number", - "minimum": 0.0, - "maximum": 1.0, - "description": "Trigger when the YES outcome price is ≤ this value (e.g. 0.05 for near-certain NO)." + "action": { + "type": "string", + "enum": [ + "subscribe", + "unsubscribe_all" + ] }, "condition_ids": { "type": "array", "items": { "type": "string" }, - "maxItems": 500, - "description": "Restrict to these markets." - }, - "position_ids": { - "type": "array", - "items": { - "type": "string" - }, - "maxItems": 500, - "description": "Restrict to these outcome token IDs." - }, - "event_slugs": { - "type": "array", - "items": { - "type": "string" - }, - "maxItems": 500, - "description": "Restrict to markets in these events." - }, - "outcomes": { - "type": "array", - "items": { - "type": "string" - }, - "maxItems": 500, - "description": "Restrict to these outcome names (e.g. [\"Yes\", \"No\"])." - }, - "position_outcome_indices": { - "type": "array", - "items": { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "maxItems": 500, - "description": "Restrict by outcome index. 0 = Yes/Up, 1 = No. Position 0 usually represents the Up/Yes side in binary markets." + "description": "Condition IDs to watch for reward changes.", + "maxItems": 500 }, - "exclude_shortterm_markets": { + "subscribe_all": { "type": "boolean", - "description": "When `true`, suppress webhooks for short-term \"updown\" markets. Default: `false`." + "description": "If true, receive ALL reward changes across all markets. Overrides condition_ids.", + "default": false } } }, - "PositionVolumeSpikeFilters": { + "OrderBookUpdateEvent": { "type": "object", - "description": "Subscription filters for the `position_volume_spike` event. `spike_ratio` is required.", + "description": "Server-pushed event: full CLOB orderbook snapshot for an outcome token. Envelope type: \"order_book_update\". Delivered whenever the book changes for a subscribed condition or position.", "required": [ - "spike_ratio" + "asset_id", + "market", + "bids", + "asks", + "timestamp", + "hash" ], "properties": { - "spike_ratio": { - "type": "number", - "exclusiveMinimum": 1.0, - "description": "**Required.** Multiplier threshold (must be > 1.0). Fires when current volume >= snapshot × ratio." + "asset_id": { + "type": "string", + "description": "Hex token ID (position / outcome token)" }, - "window_secs": { - "type": "integer", - "minimum": 1, - "maximum": 600, - "description": "Force snapshot reset after this many seconds (max 600 / 10 minutes)." + "market": { + "type": "string", + "description": "Condition ID (hex)" }, - "position_ids": { + "bids": { "type": "array", "items": { - "type": "string" + "$ref": "#/components/schemas/OrderBookLevel" }, - "maxItems": 500, - "description": "Restrict to these outcome token IDs." + "description": "Bid levels sorted best-first (highest price first)" }, - "condition_ids": { + "asks": { "type": "array", "items": { - "type": "string" + "$ref": "#/components/schemas/OrderBookLevel" }, - "maxItems": 500, - "description": "Restrict to positions within these markets." + "description": "Ask levels sorted best-first (lowest price first)" }, - "outcomes": { - "type": "array", - "items": { - "type": "string" - }, - "maxItems": 500, - "description": "Restrict to these outcome names." + "timestamp": { + "type": "integer", + "format": "int64", + "description": "Unix milliseconds from CLOB message" }, - "timeframes": { - "type": "array", - "items": { - "type": "string", - "enum": [ - "1m", - "5m", - "30m", - "1h", - "6h", - "1d", - "24h", - "7d", - "30d" - ] - }, - "maxItems": 500, - "description": "Restrict to these aggregation windows." + "hash": { + "type": "string", + "description": "Orderbook content hash — identical hash means no change" + }, + "best_bid": { + "type": [ + "number", + "null" + ], + "description": "Best bid price (0–1)" + }, + "best_ask": { + "type": [ + "number", + "null" + ], + "description": "Best ask price (0–1)" + }, + "mid_price": { + "type": [ + "number", + "null" + ], + "description": "(best_bid + best_ask) / 2" + }, + "spread": { + "type": [ + "number", + "null" + ], + "description": "best_ask − best_bid" + }, + "bid_liquidity_usd": { + "type": [ + "number", + "null" + ], + "description": "Total USD value of all bid levels" + }, + "ask_liquidity_usd": { + "type": [ + "number", + "null" + ], + "description": "Total USD value of all ask levels" + }, + "bid_levels": { + "type": [ + "integer", + "null" + ], + "description": "Number of bid price levels" + }, + "ask_levels": { + "type": [ + "integer", + "null" + ], + "description": "Number of ask price levels" } } }, + "OrderBookLevel": { + "type": "array", + "description": "A single price level: [price_string, size_string]", + "items": { + "type": "string" + }, + "minItems": 2, + "maxItems": 2 + }, "TradesStreamSubscribeMessage": { "type": "object", "description": "Subscribe to the trades stream. No filters = subscribe to all trades.", @@ -2349,9 +2277,7 @@ } } ], - "discriminator": { - "propertyName": "trade_type" - } + "discriminator": "trade_type" }, "AssetPricesSubscribeMessage": { "type": "object", @@ -3874,6686 +3800,26 @@ "description": "Filter values that were rejected (invalid format or limit exceeded)" } } - }, - "OrderBookLevel": { - "type": "array", - "description": "A single price level: [price_string, size_string]", - "items": { - "type": "string" - }, - "minItems": 2, - "maxItems": 2 - }, - "OrderBookUpdateEvent": { - "type": "object", - "description": "Server-pushed event: full CLOB orderbook snapshot for an outcome token. Envelope type: \"order_book_update\". Delivered whenever the book changes for a subscribed condition or position.", - "required": [ - "asset_id", - "market", - "bids", - "asks", - "timestamp", - "hash" - ], - "properties": { - "asset_id": { - "type": "string", - "description": "Hex token ID (position / outcome token)" - }, - "market": { - "type": "string", - "description": "Condition ID (hex)" - }, - "bids": { - "type": "array", - "items": { - "$ref": "#/components/schemas/OrderBookLevel" - }, - "description": "Bid levels sorted best-first (highest price first)" - }, - "asks": { - "type": "array", - "items": { - "$ref": "#/components/schemas/OrderBookLevel" - }, - "description": "Ask levels sorted best-first (lowest price first)" - }, - "timestamp": { - "type": "integer", - "format": "int64", - "description": "Unix milliseconds from CLOB message" - }, - "hash": { - "type": "string", - "description": "Orderbook content hash — identical hash means no change" - }, - "best_bid": { - "type": [ - "number", - "null" - ], - "description": "Best bid price (0–1)" - }, - "best_ask": { - "type": [ - "number", - "null" - ], - "description": "Best ask price (0–1)" - }, - "mid_price": { - "type": [ - "number", - "null" - ], - "description": "(best_bid + best_ask) / 2" - }, - "spread": { - "type": [ - "number", - "null" - ], - "description": "best_ask − best_bid" - }, - "bid_liquidity_usd": { - "type": [ - "number", - "null" - ], - "description": "Total USD value of all bid levels" - }, - "ask_liquidity_usd": { - "type": [ - "number", - "null" - ], - "description": "Total USD value of all ask levels" - }, - "bid_levels": { - "type": [ - "integer", - "null" - ], - "description": "Number of bid price levels" - }, - "ask_levels": { - "type": [ - "integer", - "null" - ], - "description": "Number of ask price levels" - } - } - }, - "ClobRewardsSubscribeMessage": { - "type": "object", - "description": "Subscribe to CLOB reward changes. Either provide specific condition_ids or set subscribe_all to true.", - "required": [ - "action" - ], - "properties": { - "action": { - "type": "string", - "enum": [ - "subscribe", - "unsubscribe_all" - ] - }, - "condition_ids": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Condition IDs to watch for reward changes.", - "maxItems": 500 - }, - "subscribe_all": { - "type": "boolean", - "description": "If true, receive ALL reward changes across all markets. Overrides condition_ids.", - "default": false - } - } - }, - "ClobRewardsSubscribeResponse": { - "type": "object", - "description": "Server acknowledgement for a CLOB rewards subscription. Envelope type: \"clob_rewards_stream_subscribe_response\".", - "properties": { - "condition_ids": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Accepted condition IDs" - }, - "subscribe_all": { - "type": "boolean", - "description": "Whether subscribed to all changes" - }, - "rejected": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Filter values that were rejected" - } - } - }, - "ClobRewardsUpdateEvent": { - "type": "object", - "description": "Server-pushed CLOB reward change event. Envelope type: \"clob_rewards_update\".", - "properties": { - "event_type": { - "type": "string", - "enum": [ - "added", - "removed", - "updated" - ], - "description": "Type of change" - }, - "condition_id": { - "type": "string", - "description": "Affected market condition ID" - }, - "reward": { - "type": [ - "object", - "null" - ], - "description": "Full reward state (null for 'removed' events)", - "properties": { - "condition_id": { - "type": "string" - }, - "rewards_config": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "asset_address": { - "type": "string", - "description": "Reward token address (e.g. USDC)" - }, - "start_date": { - "type": "string", - "format": "date" - }, - "end_date": { - "type": "string", - "format": "date" - }, - "rate_per_day": { - "type": "number", - "description": "Daily reward rate in USDC" - }, - "total_rewards": { - "type": "number", - "description": "Cumulative rewards distributed" - } - } - } - }, - "rewards_max_spread": { - "type": [ - "number", - "null" - ], - "description": "Max spread to qualify for rewards" - }, - "rewards_min_size": { - "type": [ - "number", - "null" - ], - "description": "Min order size to qualify for rewards" - }, - "native_daily_rate": { - "type": [ - "number", - "null" - ], - "description": "Native (non-sponsored) daily rate" - }, - "sponsored_daily_rate": { - "type": [ - "number", - "null" - ], - "description": "Sponsored daily rate" - }, - "total_daily_rate": { - "type": [ - "number", - "null" - ], - "description": "Combined daily rate (native + sponsored)" - }, - "sponsors_count": { - "type": [ - "integer", - "null" - ], - "description": "Number of sponsors" - } - } - }, - "timestamp_ms": { - "type": "integer", - "description": "Unix timestamp in milliseconds" - } - } - }, - "WebhookDeliveryEnvelope": { - "type": "object", - "description": "Outer envelope for every webhook HTTP POST delivery. The `data` field contains the event-specific payload. Delivery headers sent with every POST: `X-Webhook-ID` (subscription UUID), `X-Delivery-ID` (this attempt's UUID), `X-Event-Type` (event name string, e.g. `trader_first_trade`), `X-Attempt` (attempt number, 1-indexed). When the webhook has a secret configured, `X-Webhook-Signature: sha256=` is also included — compute HMAC-SHA256 over the raw request body using your secret to verify.", - "required": [ - "id", - "event", - "data", - "timestamp", - "webhook_id", - "attempt" - ], - "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "UUID of this specific delivery attempt (matches X-Delivery-ID header)" - }, - "event": { - "type": "string", - "description": "Event name (e.g. `trader_first_trade`). On test deliveries the suffix `_test` is appended." - }, - "data": { - "type": "object", - "description": "Event-specific payload — schema varies by event type; see the individual callback definitions" - }, - "timestamp": { - "type": "integer", - "format": "int64", - "description": "Unix timestamp in milliseconds when this delivery was created" - }, - "webhook_id": { - "type": "string", - "format": "uuid", - "description": "UUID of the webhook subscription that fired (matches X-Webhook-ID header)" - }, - "attempt": { - "type": "integer", - "minimum": 1, - "description": "Delivery attempt number. 1 = first attempt; increments on each retry." - } - } - }, - "FirstTradePayload": { - "type": "object", - "description": "Payload delivered when a tracked trader executes their first-ever trade on Polymarket", - "required": [ - "trader", - "taker", - "position_id", - "trade_id", - "hash", - "block", - "confirmed_at", - "amount_usd", - "shares_amount", - "fee", - "side", - "price", - "exchange", - "trade_type" - ], - "properties": { - "trader": { - "type": "string", - "description": "Limit-order maker wallet address (lowercase)" - }, - "taker": { - "type": "string", - "description": "Order filler wallet address (lowercase)" - }, - "position_id": { - "type": "string", - "description": "ERC-1155 outcome token ID" - }, - "condition_id": { - "type": [ - "string", - "null" - ], - "description": "Parent market condition ID (0x-prefixed hex)" - }, - "outcome": { - "type": [ - "string", - "null" - ], - "description": "Outcome name (e.g. \"Yes\", \"No\")" - }, - "outcome_index": { - "type": [ - "integer", - "null" - ], - "description": "Outcome index: 0 = Yes/Up, 1 = No" - }, - "question": { - "type": [ - "string", - "null" - ], - "description": "Market question text" - }, - "market_slug": { - "type": [ - "string", - "null" - ], - "description": "Market slug" - }, - "event_slug": { - "type": [ - "string", - "null" - ], - "description": "Parent event slug" - }, - "trade_id": { - "type": "string", - "description": "Unique trade identifier" - }, - "hash": { - "type": "string", - "description": "Transaction hash" - }, - "block": { - "type": "integer", - "format": "int64", - "description": "Block number" - }, - "confirmed_at": { - "type": "integer", - "format": "int64", - "description": "Block confirmation timestamp (Unix seconds)" - }, - "amount_usd": { - "type": "number", - "description": "USD size of the trade (6 decimal places)" - }, - "shares_amount": { - "type": "number", - "description": "Outcome shares traded (6 decimal places)" - }, - "fee": { - "type": "number", - "description": "Fee paid in USD (6 decimal places)" - }, - "side": { - "type": "string", - "enum": [ - "Buy", - "Sell" - ], - "description": "Trade direction" - }, - "price": { - "type": "number", - "minimum": 0.0, - "maximum": 1.0, - "description": "Outcome token price (0.0–1.0)" - }, - "exchange": { - "type": "string", - "description": "Exchange identifier" - }, - "trade_type": { - "type": "string", - "description": "Trade type identifier" - } - } - }, - "NewMarketPayload": { - "type": "object", - "description": "Payload delivered when a trader places their first trade in a specific market (fires once per trader+market pair)", - "required": [ - "trader", - "taker", - "position_id", - "trade_id", - "hash", - "block", - "confirmed_at", - "amount_usd", - "shares_amount", - "fee", - "side", - "price", - "exchange", - "trade_type" - ], - "properties": { - "trader": { - "type": "string", - "description": "Limit-order maker wallet address (lowercase)" - }, - "taker": { - "type": "string", - "description": "Order filler wallet address (lowercase)" - }, - "position_id": { - "type": "string", - "description": "ERC-1155 outcome token ID" - }, - "condition_id": { - "type": [ - "string", - "null" - ], - "description": "Parent market condition ID" - }, - "outcome": { - "type": [ - "string", - "null" - ], - "description": "Outcome name (e.g. \"Yes\", \"No\")" - }, - "outcome_index": { - "type": [ - "integer", - "null" - ], - "description": "Outcome index: 0 = Yes/Up, 1 = No" - }, - "question": { - "type": [ - "string", - "null" - ], - "description": "Market question text" - }, - "market_slug": { - "type": [ - "string", - "null" - ], - "description": "Market slug" - }, - "event_slug": { - "type": [ - "string", - "null" - ], - "description": "Parent event slug" - }, - "trade_id": { - "type": "string", - "description": "Unique trade identifier" - }, - "hash": { - "type": "string", - "description": "Transaction hash" - }, - "block": { - "type": "integer", - "format": "int64", - "description": "Block number" - }, - "confirmed_at": { - "type": "integer", - "format": "int64", - "description": "Block confirmation timestamp (Unix seconds)" - }, - "amount_usd": { - "type": "number", - "description": "USD size of the trade (6 decimal places)" - }, - "shares_amount": { - "type": "number", - "description": "Outcome shares traded (6 decimal places)" - }, - "fee": { - "type": "number", - "description": "Fee paid in USD (6 decimal places)" - }, - "side": { - "type": "string", - "enum": [ - "Buy", - "Sell" - ], - "description": "Trade direction" - }, - "price": { - "type": "number", - "minimum": 0.0, - "maximum": 1.0, - "description": "Outcome token price (0.0–1.0)" - }, - "probability": { - "type": [ - "number", - "null" - ], - "minimum": 0.0, - "maximum": 1.0, - "description": "Implied probability (0.0–1.0); null when outcome is unknown" - }, - "exchange": { - "type": "string", - "description": "Exchange identifier" - }, - "trade_type": { - "type": "string", - "description": "Trade type identifier" - } - } - }, - "WhaleTradePayload": { - "type": "object", - "description": "Payload delivered when a trade exceeds the configured size and probability thresholds", - "required": [ - "trader", - "taker", - "position_id", - "trade_id", - "hash", - "block", - "confirmed_at", - "amount_usd", - "shares_amount", - "fee", - "side", - "price", - "exchange", - "trade_type" - ], - "properties": { - "trader": { - "type": "string", - "description": "Limit-order maker wallet address (lowercase)" - }, - "taker": { - "type": "string", - "description": "Order filler wallet address (lowercase)" - }, - "position_id": { - "type": "string", - "description": "ERC-1155 outcome token ID" - }, - "condition_id": { - "type": [ - "string", - "null" - ], - "description": "Parent market condition ID" - }, - "outcome": { - "type": [ - "string", - "null" - ], - "description": "Outcome name (e.g. \"Yes\", \"No\")" - }, - "outcome_index": { - "type": [ - "integer", - "null" - ], - "description": "Outcome index: 0 = Yes/Up, 1 = No" - }, - "question": { - "type": [ - "string", - "null" - ], - "description": "Market question text" - }, - "market_slug": { - "type": [ - "string", - "null" - ], - "description": "Market slug" - }, - "event_slug": { - "type": [ - "string", - "null" - ], - "description": "Parent event slug" - }, - "trade_id": { - "type": "string", - "description": "Unique trade identifier" - }, - "hash": { - "type": "string", - "description": "Transaction hash" - }, - "block": { - "type": "integer", - "format": "int64", - "description": "Block number" - }, - "confirmed_at": { - "type": "integer", - "format": "int64", - "description": "Block confirmation timestamp (Unix seconds)" - }, - "amount_usd": { - "type": "number", - "description": "USD size of the trade (6 decimal places)" - }, - "shares_amount": { - "type": "number", - "description": "Outcome shares traded (6 decimal places)" - }, - "fee": { - "type": "number", - "description": "Fee paid in USD (6 decimal places)" - }, - "side": { - "type": "string", - "enum": [ - "Buy", - "Sell" - ], - "description": "Trade direction" - }, - "price": { - "type": "number", - "minimum": 0.0, - "maximum": 1.0, - "description": "Outcome token price (0.0–1.0)" - }, - "probability": { - "type": [ - "number", - "null" - ], - "minimum": 0.0, - "maximum": 1.0, - "description": "Implied probability (0.0–1.0); null when outcome is unknown" - }, - "exchange": { - "type": "string", - "description": "Exchange identifier" - }, - "trade_type": { - "type": "string", - "description": "Trade type identifier" - } - } - }, - "NewTradePayload": { - "type": "object", - "description": "Payload delivered on every order-filled trade", - "required": [ - "trader", - "taker", - "position_id", - "trade_id", - "hash", - "block", - "confirmed_at", - "amount_usd", - "shares_amount", - "fee", - "side", - "price", - "exchange", - "trade_type" - ], - "properties": { - "trader": { - "type": "string", - "description": "Limit-order maker wallet address (lowercase)" - }, - "taker": { - "type": "string", - "description": "Order filler wallet address (lowercase)" - }, - "position_id": { - "type": "string", - "description": "ERC-1155 outcome token ID" - }, - "condition_id": { - "type": [ - "string", - "null" - ], - "description": "Parent market condition ID" - }, - "outcome": { - "type": [ - "string", - "null" - ], - "description": "Outcome name (e.g. \"Yes\", \"No\")" - }, - "outcome_index": { - "type": [ - "integer", - "null" - ], - "description": "Outcome index: 0 = Yes/Up, 1 = No" - }, - "question": { - "type": [ - "string", - "null" - ], - "description": "Market question text" - }, - "market_slug": { - "type": [ - "string", - "null" - ], - "description": "Market slug" - }, - "event_slug": { - "type": [ - "string", - "null" - ], - "description": "Parent event slug" - }, - "trade_id": { - "type": "string", - "description": "Unique trade identifier" - }, - "hash": { - "type": "string", - "description": "Transaction hash" - }, - "block": { - "type": "integer", - "format": "int64", - "description": "Block number" - }, - "confirmed_at": { - "type": "integer", - "format": "int64", - "description": "Block confirmation timestamp (Unix seconds)" - }, - "amount_usd": { - "type": "number", - "description": "USD size of the trade (6 decimal places)" - }, - "shares_amount": { - "type": "number", - "description": "Outcome shares traded (6 decimal places)" - }, - "fee": { - "type": "number", - "description": "Fee paid in USD (6 decimal places)" - }, - "side": { - "type": "string", - "enum": [ - "Buy", - "Sell" - ], - "description": "Trade direction" - }, - "price": { - "type": "number", - "minimum": 0.0, - "maximum": 1.0, - "description": "Outcome token price (0.0–1.0)" - }, - "probability": { - "type": [ - "number", - "null" - ], - "minimum": 0.0, - "maximum": 1.0, - "description": "Implied probability (0.0–1.0); null when outcome is unknown" - }, - "exchange": { - "type": "string", - "description": "Exchange identifier" - }, - "trade_type": { - "type": "string", - "description": "Trade type identifier" - } - } - }, - "GlobalPnlPayload": { - "type": "object", - "description": "Payload delivered when a trader's global PnL (across all markets) crosses a configured threshold", - "required": [ - "timeframe" - ], - "properties": { - "trader": { - "type": [ - "string", - "null" - ], - "description": "Trader wallet address (lowercase)" - }, - "timeframe": { - "type": "string", - "enum": [ - "1d", - "7d", - "30d", - "lifetime" - ], - "description": "PnL aggregation window" - }, - "realized_pnl_usd": { - "type": [ - "number", - "null" - ], - "description": "Realized PnL in USD (positive = profit, negative = loss)" - }, - "events_traded": { - "type": [ - "integer", - "null" - ], - "format": "int64", - "description": "Number of distinct events traded" - }, - "markets_traded": { - "type": [ - "integer", - "null" - ], - "format": "int64", - "description": "Number of distinct markets traded" - }, - "total_buys": { - "type": [ - "integer", - "null" - ], - "format": "int64", - "description": "Total buy transactions" - }, - "total_sells": { - "type": [ - "integer", - "null" - ], - "format": "int64", - "description": "Total sell transactions" - }, - "total_redemptions": { - "type": [ - "integer", - "null" - ], - "format": "int64", - "description": "Total redemption transactions" - }, - "total_merges": { - "type": [ - "integer", - "null" - ], - "format": "int64", - "description": "Total merge transactions" - }, - "total_volume_usd": { - "type": [ - "number", - "null" - ], - "description": "Total USD volume (buys + sells + redemptions + merges)" - }, - "buy_volume_usd": { - "type": [ - "number", - "null" - ], - "description": "Total buy volume in USD" - }, - "sell_volume_usd": { - "type": [ - "number", - "null" - ], - "description": "Total sell volume in USD" - }, - "redemption_volume_usd": { - "type": [ - "number", - "null" - ], - "description": "Total redemption volume in USD" - }, - "merge_volume_usd": { - "type": [ - "number", - "null" - ], - "description": "Total merge volume in USD" - }, - "markets_won": { - "type": [ - "integer", - "null" - ], - "format": "int64", - "description": "Number of markets where trader realised a profit" - }, - "markets_lost": { - "type": [ - "integer", - "null" - ], - "format": "int64", - "description": "Number of markets where trader realised a loss" - }, - "market_win_rate_pct": { - "type": [ - "number", - "null" - ], - "description": "Market win rate as a percentage (0.0–100.0)" - }, - "avg_pnl_per_market": { - "type": [ - "number", - "null" - ], - "description": "Average PnL per market in USD" - }, - "avg_pnl_per_trade": { - "type": [ - "number", - "null" - ], - "description": "Average PnL per trade in USD" - }, - "avg_hold_time_seconds": { - "type": [ - "number", - "null" - ], - "description": "Average hold time across all positions (seconds)" - }, - "total_fees": { - "type": [ - "number", - "null" - ], - "description": "Total fees paid in USD" - }, - "best_trade_pnl_usd": { - "type": [ - "number", - "null" - ], - "description": "Best single-trade PnL in USD" - }, - "best_trade_condition_id": { - "type": [ - "string", - "null" - ], - "description": "Condition ID of the best trade" - }, - "first_trade_at": { - "type": [ - "integer", - "null" - ], - "format": "int64", - "description": "Timestamp of the first trade (Unix seconds)" - }, - "last_trade_at": { - "type": [ - "integer", - "null" - ], - "format": "int64", - "description": "Timestamp of the most recent trade (Unix seconds)" - } - } - }, - "MarketPnlPayload": { - "type": "object", - "description": "Payload delivered when a trader's per-market PnL crosses a configured threshold", - "required": [ - "timeframe" - ], - "properties": { - "trader": { - "type": [ - "string", - "null" - ], - "description": "Trader wallet address (lowercase)" - }, - "condition_id": { - "type": [ - "string", - "null" - ], - "description": "Market condition ID" - }, - "event_slug": { - "type": [ - "string", - "null" - ], - "description": "Parent event slug" - }, - "timeframe": { - "type": "string", - "enum": [ - "1d", - "7d", - "30d", - "lifetime" - ], - "description": "PnL aggregation window" - }, - "outcomes_traded": { - "type": [ - "integer", - "null" - ], - "format": "int64", - "description": "Number of distinct outcomes traded in this market" - }, - "total_buys": { - "type": [ - "integer", - "null" - ], - "format": "int64" - }, - "total_sells": { - "type": [ - "integer", - "null" - ], - "format": "int64" - }, - "total_redemptions": { - "type": [ - "integer", - "null" - ], - "format": "int64" - }, - "total_merges": { - "type": [ - "integer", - "null" - ], - "format": "int64" - }, - "buy_usd": { - "type": [ - "number", - "null" - ], - "description": "Total buy volume in USD" - }, - "sell_usd": { - "type": [ - "number", - "null" - ], - "description": "Total sell volume in USD" - }, - "redemption_usd": { - "type": [ - "number", - "null" - ], - "description": "Total redemption volume in USD" - }, - "merge_usd": { - "type": [ - "number", - "null" - ], - "description": "Total merge volume in USD" - }, - "realized_pnl_usd": { - "type": [ - "number", - "null" - ], - "description": "Realized PnL in USD for this market" - }, - "winning_outcomes": { - "type": [ - "integer", - "null" - ], - "format": "int64", - "description": "Number of outcomes with positive PnL" - }, - "total_fees": { - "type": [ - "number", - "null" - ], - "description": "Total fees paid in USD for this market" - }, - "first_trade_at": { - "type": [ - "integer", - "null" - ], - "format": "int64", - "description": "Timestamp of first trade in market (Unix seconds)" - }, - "last_trade_at": { - "type": [ - "integer", - "null" - ], - "format": "int64", - "description": "Timestamp of most recent trade in market (Unix seconds)" - } - } - }, - "EventPnlPayload": { - "type": "object", - "description": "Payload delivered when a trader's per-event PnL crosses a configured threshold", - "required": [ - "timeframe" - ], - "properties": { - "trader": { - "type": [ - "string", - "null" - ], - "description": "Trader wallet address (lowercase)" - }, - "event_slug": { - "type": [ - "string", - "null" - ], - "description": "Event slug" - }, - "timeframe": { - "type": "string", - "enum": [ - "1d", - "7d", - "30d", - "lifetime" - ], - "description": "PnL aggregation window" - }, - "markets_traded": { - "type": [ - "integer", - "null" - ], - "format": "int64", - "description": "Number of distinct markets traded in this event" - }, - "outcomes_traded": { - "type": [ - "integer", - "null" - ], - "format": "int64" - }, - "total_buys": { - "type": [ - "integer", - "null" - ], - "format": "int64" - }, - "total_sells": { - "type": [ - "integer", - "null" - ], - "format": "int64" - }, - "total_redemptions": { - "type": [ - "integer", - "null" - ], - "format": "int64" - }, - "total_merges": { - "type": [ - "integer", - "null" - ], - "format": "int64" - }, - "total_volume_usd": { - "type": [ - "number", - "null" - ], - "description": "Total volume in USD" - }, - "buy_usd": { - "type": [ - "number", - "null" - ] - }, - "sell_usd": { - "type": [ - "number", - "null" - ] - }, - "redemption_usd": { - "type": [ - "number", - "null" - ] - }, - "merge_usd": { - "type": [ - "number", - "null" - ] - }, - "realized_pnl_usd": { - "type": [ - "number", - "null" - ], - "description": "Realized PnL in USD for this event" - }, - "winning_markets": { - "type": [ - "integer", - "null" - ], - "format": "int64" - }, - "losing_markets": { - "type": [ - "integer", - "null" - ], - "format": "int64" - }, - "total_fees": { - "type": [ - "number", - "null" - ] - }, - "first_trade_at": { - "type": [ - "integer", - "null" - ], - "format": "int64", - "description": "Unix seconds" - }, - "last_trade_at": { - "type": [ - "integer", - "null" - ], - "format": "int64", - "description": "Unix seconds" - } - } - }, - "ConditionMetricsPayload": { - "type": "object", - "description": "Payload delivered when a market's volume or transaction metrics cross a configured threshold", - "properties": { - "condition_id": { - "type": [ - "string", - "null" - ], - "description": "Market condition ID" - }, - "timeframe": { - "type": [ - "string", - "null" - ], - "description": "Aggregation window (e.g. \"1h\", \"24h\")" - }, - "volume_usd": { - "type": [ - "number", - "null" - ], - "description": "Total trading volume in USD for this timeframe" - }, - "fees": { - "type": [ - "number", - "null" - ], - "description": "Total fees collected in USD" - }, - "txns": { - "type": [ - "integer", - "null" - ], - "format": "int64", - "description": "Total number of transactions" - }, - "unique_traders": { - "type": [ - "integer", - "null" - ], - "format": "int64", - "description": "Number of unique traders" - } - } - }, - "EventMetricsPayload": { - "type": "object", - "description": "Payload delivered when an event's aggregated volume or transaction metrics cross a configured threshold", - "properties": { - "event_slug": { - "type": [ - "string", - "null" - ], - "description": "Event slug" - }, - "timeframe": { - "type": [ - "string", - "null" - ], - "description": "Aggregation window (e.g. \"1h\", \"24h\")" - }, - "volume_usd": { - "type": [ - "number", - "null" - ], - "description": "Total aggregated volume across all markets in the event (USD)" - }, - "fees": { - "type": [ - "number", - "null" - ], - "description": "Total fees collected in USD" - }, - "txns": { - "type": [ - "integer", - "null" - ], - "format": "int64", - "description": "Total number of transactions" - }, - "unique_traders": { - "type": [ - "integer", - "null" - ], - "format": "int64", - "description": "Number of unique traders" - } - } - }, - "PositionMetricsPayload": { - "type": "object", - "description": "Payload delivered when a position's volume or transaction metrics cross a configured threshold", - "properties": { - "position_id": { - "type": [ - "string", - "null" - ], - "description": "ERC-1155 outcome token ID" - }, - "outcome": { - "type": [ - "string", - "null" - ], - "description": "Outcome name (e.g. \"Yes\", \"No\")" - }, - "outcome_index": { - "type": [ - "integer", - "null" - ], - "format": "int16", - "description": "Outcome index" - }, - "timeframe": { - "type": [ - "string", - "null" - ], - "description": "Aggregation window (e.g. \"1h\", \"24h\")" - }, - "volume_usd": { - "type": [ - "number", - "null" - ], - "description": "Total trading volume in USD" - }, - "buy_volume_usd": { - "type": [ - "number", - "null" - ], - "description": "Buy volume in USD" - }, - "sell_volume_usd": { - "type": [ - "number", - "null" - ], - "description": "Sell volume in USD" - }, - "fees": { - "type": [ - "number", - "null" - ], - "description": "Total fees in USD" - }, - "txns": { - "type": [ - "integer", - "null" - ], - "format": "int64" - }, - "buys": { - "type": [ - "integer", - "null" - ], - "format": "int64" - }, - "sells": { - "type": [ - "integer", - "null" - ], - "format": "int64" - }, - "unique_traders": { - "type": [ - "integer", - "null" - ], - "format": "int64" - }, - "price_open": { - "type": [ - "number", - "null" - ], - "minimum": 0.0, - "maximum": 1.0 - }, - "price_close": { - "type": [ - "number", - "null" - ], - "minimum": 0.0, - "maximum": 1.0 - }, - "price_high": { - "type": [ - "number", - "null" - ], - "minimum": 0.0, - "maximum": 1.0 - }, - "price_low": { - "type": [ - "number", - "null" - ], - "minimum": 0.0, - "maximum": 1.0 - }, - "probability_open": { - "type": [ - "number", - "null" - ], - "minimum": 0.0, - "maximum": 1.0 - }, - "probability_close": { - "type": [ - "number", - "null" - ], - "minimum": 0.0, - "maximum": 1.0 - }, - "probability_high": { - "type": [ - "number", - "null" - ], - "minimum": 0.0, - "maximum": 1.0 - }, - "probability_low": { - "type": [ - "number", - "null" - ], - "minimum": 0.0, - "maximum": 1.0 - } - } - }, - "VolumeMilestonePayload": { - "type": "object", - "description": "Payload delivered when a market's trading volume crosses a USD milestone in the specified timeframe", - "required": [ - "condition_id", - "timeframe", - "milestone_usd", - "current_volume_usd", - "fees", - "txns" - ], - "properties": { - "condition_id": { - "type": "string", - "description": "Market condition ID" - }, - "timeframe": { - "type": "string", - "description": "Aggregation window that crossed the milestone (e.g. \"1h\", \"24h\")" - }, - "milestone_usd": { - "type": "number", - "description": "The USD milestone amount that was crossed" - }, - "current_volume_usd": { - "type": "number", - "description": "Current volume at time of trigger (USD)" - }, - "fees": { - "type": "number", - "description": "Total fees in USD for this timeframe" - }, - "txns": { - "type": "integer", - "format": "int64", - "description": "Total transactions in this timeframe" - } - } - }, - "EventVolumeMilestonePayload": { - "type": "object", - "description": "Payload delivered when an event's aggregated trading volume crosses a USD milestone", - "required": [ - "event_slug", - "timeframe", - "milestone_usd", - "current_volume_usd", - "fees", - "txns" - ], - "properties": { - "event_slug": { - "type": "string", - "description": "Event slug" - }, - "timeframe": { - "type": "string", - "description": "Aggregation window (e.g. \"1h\", \"24h\")" - }, - "milestone_usd": { - "type": "number", - "description": "The USD milestone amount that was crossed" - }, - "current_volume_usd": { - "type": "number", - "description": "Current aggregated event volume at time of trigger (USD)" - }, - "fees": { - "type": "number", - "description": "Total fees in USD for this timeframe" - }, - "txns": { - "type": "integer", - "format": "int64", - "description": "Total transactions in this timeframe" - } - } - }, - "PositionVolumeMilestonePayload": { - "type": "object", - "description": "Payload delivered when a position's trading volume crosses a USD milestone", - "required": [ - "position_id", - "timeframe", - "milestone_usd", - "current_volume_usd", - "buy_volume_usd", - "sell_volume_usd", - "fees", - "txns", - "buys", - "sells" - ], - "properties": { - "condition_id": { - "type": [ - "string", - "null" - ], - "description": "Parent market condition ID" - }, - "position_id": { - "type": "string", - "description": "ERC-1155 outcome token ID" - }, - "outcome": { - "type": [ - "string", - "null" - ], - "description": "Outcome name (e.g. \"Yes\", \"No\")" - }, - "outcome_index": { - "type": [ - "integer", - "null" - ], - "format": "int16", - "description": "Outcome index" - }, - "timeframe": { - "type": "string", - "description": "Aggregation window (e.g. \"1h\", \"24h\")" - }, - "milestone_usd": { - "type": "number", - "description": "The USD milestone amount that was crossed" - }, - "current_volume_usd": { - "type": "number", - "description": "Current position volume at time of trigger (USD)" - }, - "buy_volume_usd": { - "type": "number", - "description": "Buy volume in USD for this timeframe" - }, - "sell_volume_usd": { - "type": "number", - "description": "Sell volume in USD for this timeframe" - }, - "fees": { - "type": "number", - "description": "Total fees in USD" - }, - "txns": { - "type": "integer", - "format": "int64" - }, - "buys": { - "type": "integer", - "format": "int64" - }, - "sells": { - "type": "integer", - "format": "int64" - } - } - }, - "ProbabilitySpikePayload": { - "type": "object", - "required": [ - "position_id", - "previous_probability", - "current_probability", - "spike_direction", - "spike_pct" - ], - "properties": { - "position_id": { - "type": "string", - "description": "Outcome token ID" - }, - "condition_id": { - "type": [ - "string", - "null" - ], - "description": "Market condition ID" - }, - "event_slug": { - "type": [ - "string", - "null" - ], - "description": "Event slug" - }, - "outcome": { - "type": [ - "string", - "null" - ], - "description": "Outcome name (e.g. \"Yes\", \"No\")" - }, - "outcome_index": { - "type": [ - "integer", - "null" - ], - "format": "int16", - "description": "Outcome index" - }, - "previous_probability": { - "type": "number", - "description": "Probability at the start of the observation window (baseline snapshot, 0.0–1.0)" - }, - "current_probability": { - "type": "number", - "description": "Current probability that triggered the spike (0.0–1.0)" - }, - "spike_direction": { - "type": "string", - "enum": [ - "up", - "down" - ], - "description": "`\"up\"` = probability rising, `\"down\"` = probability falling" - }, - "spike_pct": { - "type": "number", - "description": "Percentage move that triggered this notification. Positive = up, negative = down." - } - } - }, - "PriceSpikePayload": { - "type": "object", - "required": [ - "position_id", - "previous_price", - "current_price", - "spike_direction", - "spike_pct" - ], - "properties": { - "position_id": { - "type": "string", - "description": "Outcome token ID" - }, - "condition_id": { - "type": [ - "string", - "null" - ], - "description": "Market condition ID" - }, - "event_slug": { - "type": [ - "string", - "null" - ], - "description": "Event slug" - }, - "outcome": { - "type": [ - "string", - "null" - ], - "description": "Outcome name (e.g. \"Yes\", \"No\")" - }, - "outcome_index": { - "type": [ - "integer", - "null" - ], - "format": "int16", - "description": "Outcome index" - }, - "previous_price": { - "type": "number", - "description": "Price at the start of the observation window (baseline snapshot, 0.0–1.0)" - }, - "current_price": { - "type": "number", - "description": "Current price that triggered the spike (0.0–1.0)" - }, - "spike_direction": { - "type": "string", - "enum": [ - "up", - "down" - ], - "description": "`\"up\"` = price rising, `\"down\"` = price falling" - }, - "spike_pct": { - "type": "number", - "description": "Percentage move that triggered this notification. Positive = up, negative = down." - } - } - }, - "MarketVolumeSpikePayload": { - "type": "object", - "description": "Payload delivered when a market's volume has spiked since the last snapshot", - "required": [ - "condition_id", - "timeframe", - "current_volume_usd", - "snapshot_volume_usd", - "delta_volume_usd", - "spike_pct", - "txns", - "fees" - ], - "properties": { - "condition_id": { - "type": "string", - "description": "Market condition ID" - }, - "timeframe": { - "type": "string", - "description": "Aggregation window (e.g. \"1h\", \"24h\")" - }, - "current_volume_usd": { - "type": "number", - "description": "Current volume at the time of the spike (USD)" - }, - "snapshot_volume_usd": { - "type": "number", - "description": "Volume at the snapshot baseline (USD)" - }, - "delta_volume_usd": { - "type": "number", - "description": "New volume since the snapshot that triggered this notification (USD)" - }, - "spike_pct": { - "type": "number", - "description": "Volume growth as a percentage of the snapshot (e.g. 200.0 means volume tripled)" - }, - "txns": { - "type": "integer", - "format": "int64", - "description": "Total transactions in this timeframe" - }, - "fees": { - "type": "number", - "description": "Total fees in USD for this timeframe" - } - } - }, - "EventVolumeSpikePayload": { - "type": "object", - "description": "Payload delivered when an event's aggregated volume has spiked since the last snapshot", - "required": [ - "event_slug", - "timeframe", - "current_volume_usd", - "snapshot_volume_usd", - "delta_volume_usd", - "spike_pct", - "txns", - "fees" - ], - "properties": { - "event_slug": { - "type": "string", - "description": "Event slug" - }, - "timeframe": { - "type": "string", - "description": "Aggregation window (e.g. \"1h\", \"24h\")" - }, - "current_volume_usd": { - "type": "number", - "description": "Current aggregated event volume at time of the spike (USD)" - }, - "snapshot_volume_usd": { - "type": "number", - "description": "Volume at the snapshot baseline (USD)" - }, - "delta_volume_usd": { - "type": "number", - "description": "New volume since the snapshot that triggered this notification (USD)" - }, - "spike_pct": { - "type": "number", - "description": "Volume growth as a percentage of the snapshot (e.g. 200.0 means volume tripled)" - }, - "txns": { - "type": "integer", - "format": "int64" - }, - "fees": { - "type": "number" - } - } - }, - "PositionVolumeSpikePayload": { - "type": "object", - "description": "Payload delivered when a position's volume has spiked since the last snapshot", - "required": [ - "position_id", - "condition_id", - "timeframe", - "current_volume_usd", - "snapshot_volume_usd", - "delta_volume_usd", - "spike_pct", - "txns", - "fees" - ], - "properties": { - "position_id": { - "type": "string", - "description": "ERC-1155 outcome token ID" - }, - "condition_id": { - "type": "string", - "description": "Parent market condition ID" - }, - "outcome": { - "type": [ - "string", - "null" - ], - "description": "Outcome name (e.g. \"Yes\", \"No\")" - }, - "outcome_index": { - "type": [ - "integer", - "null" - ], - "format": "int16" - }, - "timeframe": { - "type": "string", - "description": "Aggregation window (e.g. \"1h\", \"24h\")" - }, - "current_volume_usd": { - "type": "number", - "description": "Current position volume at the time of the spike (USD)" - }, - "snapshot_volume_usd": { - "type": "number", - "description": "Volume at the snapshot baseline (USD)" - }, - "delta_volume_usd": { - "type": "number", - "description": "New volume since the snapshot that triggered this notification (USD)" - }, - "spike_pct": { - "type": "number", - "description": "Volume growth as a percentage of the snapshot (e.g. 200.0 means volume tripled)" - }, - "txns": { - "type": "integer", - "format": "int64" - }, - "fees": { - "type": "number" - } - } - }, - "CloseToBondPayload": { - "type": "object", - "description": "Payload delivered when a trade occurs at a near-certain-outcome price", - "required": [ - "trader", - "taker", - "position_id", - "trade_id", - "hash", - "block", - "confirmed_at", - "amount_usd", - "shares_amount", - "fee", - "side", - "price", - "bond_side", - "threshold" - ], - "properties": { - "trader": { - "type": "string", - "description": "Limit-order maker wallet address (lowercase)" - }, - "taker": { - "type": "string", - "description": "Order filler wallet address (lowercase)" - }, - "position_id": { - "type": "string", - "description": "ERC-1155 outcome token ID" - }, - "condition_id": { - "type": [ - "string", - "null" - ], - "description": "Parent market condition ID" - }, - "outcome": { - "type": [ - "string", - "null" - ], - "description": "Outcome name (e.g. \"Yes\", \"No\")" - }, - "outcome_index": { - "type": [ - "integer", - "null" - ], - "description": "0 = Yes/Up, 1 = No" - }, - "question": { - "type": [ - "string", - "null" - ] - }, - "market_slug": { - "type": [ - "string", - "null" - ] - }, - "event_slug": { - "type": [ - "string", - "null" - ] - }, - "trade_id": { - "type": "string" - }, - "hash": { - "type": "string", - "description": "Transaction hash" - }, - "block": { - "type": "integer", - "format": "int64" - }, - "confirmed_at": { - "type": "integer", - "format": "int64", - "description": "Unix seconds" - }, - "amount_usd": { - "type": "number", - "description": "USD size of the trade" - }, - "shares_amount": { - "type": "number" - }, - "fee": { - "type": "number", - "description": "Fee paid in USD" - }, - "side": { - "type": "string", - "enum": [ - "Buy", - "Sell" - ] - }, - "price": { - "type": "number", - "minimum": 0.0, - "maximum": 1.0, - "description": "Price that triggered the notification (0.0–1.0)" - }, - "probability": { - "type": [ - "number", - "null" - ], - "minimum": 0.0, - "maximum": 1.0, - "description": "Implied probability (0.0–1.0)" - }, - "bond_side": { - "type": "string", - "enum": [ - "high", - "low" - ], - "description": "\"high\" when near YES (price ≥ threshold), \"low\" when near NO (price ≤ threshold)" - }, - "threshold": { - "type": "number", - "description": "The probability threshold from the subscription filter that was breached" - } - } - }, - "MarketCreatedOutcome": { - "type": "object", - "description": "An outcome entry within a newly created market", - "required": [ - "index", - "name", - "position_id" - ], - "properties": { - "index": { - "type": "integer", - "description": "Outcome index (0 = Yes, 1 = No)" - }, - "name": { - "type": "string", - "description": "Outcome name (e.g. \"Yes\", \"No\")" - }, - "position_id": { - "type": "string", - "description": "ERC-1155 position token ID for this outcome" - } - } - }, - "MarketCreatedPayload": { - "type": "object", - "description": "Payload delivered when a new prediction market is detected on-chain and enriched with Gamma API metadata", - "required": [ - "condition_id", - "market_slug", - "outcomes", - "question", - "description", - "tags", - "neg_risk" - ], - "properties": { - "condition_id": { - "type": "string", - "description": "Condition ID (0x-prefixed hex, lowercase)" - }, - "market_slug": { - "type": "string", - "description": "Market slug" - }, - "event_slug": { - "type": [ - "string", - "null" - ], - "description": "Parent event slug" - }, - "event_id": { - "type": [ - "string", - "null" - ], - "description": "Parent event ID" - }, - "event_title": { - "type": [ - "string", - "null" - ], - "description": "Parent event title" - }, - "series_slug": { - "type": [ - "string", - "null" - ], - "description": "Series slug (for recurring markets)" - }, - "outcomes": { - "type": "array", - "description": "List of market outcomes with their position IDs", - "items": { - "$ref": "#/components/schemas/MarketCreatedOutcome" - } - }, - "question": { - "type": "string", - "description": "Full market question text" - }, - "title": { - "type": [ - "string", - "null" - ], - "description": "Short display title" - }, - "description": { - "type": "string", - "description": "Market description" - }, - "category": { - "type": [ - "string", - "null" - ], - "description": "Market category (e.g. \"Sports\", \"Politics\")" - }, - "tags": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Market tags" - }, - "image_url": { - "type": [ - "string", - "null" - ], - "description": "Cover image URL" - }, - "neg_risk": { - "type": "boolean", - "description": "Whether this is a neg-risk market" - } - } - }, - "AssetPriceTickPayload": { - "type": "object", - "description": "Payload delivered on every raw Chainlink price tick for a tracked crypto asset", - "required": [ - "symbol", - "price", - "timestamp_ms" - ], - "properties": { - "symbol": { - "type": "string", - "enum": [ - "BTC", - "ETH", - "SOL", - "XRP", - "DOGE", - "BNB", - "HYPE" - ], - "description": "Asset symbol" - }, - "price": { - "type": "number", - "description": "Current asset price in USD from the Chainlink feed" - }, - "timestamp_ms": { - "type": "integer", - "format": "int64", - "description": "Tick timestamp (milliseconds since Unix epoch)" - } - } - }, - "AssetPriceWindowUpdatePayload": { - "type": "object", - "description": "Payload delivered twice per candle — once on open and once on close. `close_price` is 0.0 on the \"open\" update.", - "required": [ - "symbol", - "variant", - "start_time", - "end_time", - "open_price", - "close_price", - "update_type" - ], - "properties": { - "symbol": { - "type": "string", - "enum": [ - "BTC", - "ETH", - "SOL", - "XRP", - "DOGE", - "BNB", - "HYPE" - ], - "description": "Asset symbol" - }, - "variant": { - "type": "string", - "enum": [ - "5m", - "15m", - "1h", - "4h", - "1d", - "24h" - ], - "description": "Candle / window size" - }, - "start_time": { - "type": "integer", - "format": "int64", - "description": "Window start timestamp (milliseconds since Unix epoch)" - }, - "end_time": { - "type": "integer", - "format": "int64", - "description": "Window end timestamp (milliseconds since Unix epoch)" - }, - "open_price": { - "type": "number", - "description": "Opening price at start_time (USD)" - }, - "close_price": { - "type": "number", - "description": "Closing price at end_time (USD). 0.0 when update_type is \"open\" (not yet available)." - }, - "update_type": { - "type": "string", - "enum": [ - "open", - "close" - ], - "description": "\"open\" when the candle opens, \"close\" when it closes with a confirmed price" - } - } - }, - "TraderFirstTradeFilters": { - "type": "object", - "description": "Subscription filters for the `trader_first_trade` event. All fields are optional.", - "properties": { - "wallet_addresses": { - "type": "array", - "items": { - "type": "string" - }, - "maxItems": 500, - "description": "Only fire for trades by these wallet addresses (lowercase). Empty = all traders." - }, - "condition_ids": { - "type": "array", - "items": { - "type": "string" - }, - "maxItems": 500, - "description": "Restrict to trades in these markets. Empty = all markets." - }, - "event_slugs": { - "type": "array", - "items": { - "type": "string" - }, - "maxItems": 500, - "description": "Restrict to trades in markets belonging to these events." - }, - "min_usd_value": { - "type": "number", - "description": "Minimum trade size in USD. Omit to match all sizes." - }, - "min_probability": { - "type": "number", - "minimum": 0.0, - "maximum": 1.0, - "description": "Only fire when the outcome probability is ≥ this value." - }, - "max_probability": { - "type": "number", - "minimum": 0.0, - "maximum": 1.0, - "description": "Only fire when the outcome probability is ≤ this value." - }, - "exclude_shortterm_markets": { - "type": "boolean", - "description": "When `true`, suppress webhooks for short-term \"updown\" markets (event slugs containing `updown`). Default: `false`." - } - } - }, - "TraderNewMarketFilters": { - "type": "object", - "description": "Subscription filters for the `trader_new_market` event. All fields are optional.", - "properties": { - "wallet_addresses": { - "type": "array", - "items": { - "type": "string" - }, - "maxItems": 500, - "description": "Only fire for these wallet addresses (lowercase). Empty = all traders." - }, - "condition_ids": { - "type": "array", - "items": { - "type": "string" - }, - "maxItems": 500, - "description": "Restrict to these markets." - }, - "event_slugs": { - "type": "array", - "items": { - "type": "string" - }, - "maxItems": 500, - "description": "Restrict to markets belonging to these events." - }, - "exclude_shortterm_markets": { - "type": "boolean", - "description": "When `true`, suppress webhooks for short-term \"updown\" markets. Default: `false`." - } - } - }, - "TraderWhaleTradeFilters": { - "type": "object", - "description": "Subscription filters for the `trader_whale_trade` event. All fields are optional.", - "properties": { - "wallet_addresses": { - "type": "array", - "items": { - "type": "string" - }, - "maxItems": 500, - "description": "Only fire for trades by these wallet addresses. Empty = all traders." - }, - "condition_ids": { - "type": "array", - "items": { - "type": "string" - }, - "maxItems": 500, - "description": "Restrict to these markets." - }, - "event_slugs": { - "type": "array", - "items": { - "type": "string" - }, - "maxItems": 500, - "description": "Restrict to markets belonging to these events." - }, - "min_usd_value": { - "type": "number", - "default": 0, - "description": "Minimum trade size in USD. Defaults to 0 (matches all trades)." - }, - "min_probability": { - "type": "number", - "minimum": 0.0, - "maximum": 1.0, - "description": "Only fire when outcome probability is ≥ this value." - }, - "max_probability": { - "type": "number", - "minimum": 0.0, - "maximum": 1.0, - "description": "Only fire when outcome probability is ≤ this value." - }, - "exclude_shortterm_markets": { - "type": "boolean", - "description": "When `true`, suppress webhooks for short-term \"updown\" markets. Default: `false`." - } - } - }, - "TraderNewTradeFilters": { - "type": "object", - "description": "Subscription filters for the `trader_new_trade` event. All fields are optional.", - "properties": { - "wallet_addresses": { - "type": "array", - "items": { - "type": "string" - }, - "maxItems": 500, - "description": "Only fire for trades by these wallet addresses. Empty = all traders." - }, - "condition_ids": { - "type": "array", - "items": { - "type": "string" - }, - "maxItems": 500, - "description": "Restrict to these markets." - }, - "event_slugs": { - "type": "array", - "items": { - "type": "string" - }, - "maxItems": 500, - "description": "Restrict to markets belonging to these events." - }, - "min_usd_value": { - "type": "number", - "default": 0, - "description": "Minimum trade size in USD. Defaults to 0 (matches all trades)." - }, - "min_probability": { - "type": "number", - "minimum": 0.0, - "maximum": 1.0, - "description": "Only fire when outcome probability is ≥ this value." - }, - "max_probability": { - "type": "number", - "minimum": 0.0, - "maximum": 1.0, - "description": "Only fire when outcome probability is ≤ this value." - }, - "exclude_shortterm_markets": { - "type": "boolean", - "description": "When `true`, suppress webhooks for short-term \"updown\" markets. Default: `false`." - } - } - }, - "TraderGlobalPnlFilters": { - "type": "object", - "description": "Subscription filters for the `trader_global_pnl` event. All fields are optional.", - "properties": { - "traders": { - "type": "array", - "items": { - "type": "string" - }, - "maxItems": 500, - "description": "Track only these trader wallet addresses. Empty = all traders." - }, - "min_realized_pnl_usd": { - "type": "number", - "description": "Only fire when realized PnL ≥ this value (USD). Use negative values for loss thresholds." - }, - "max_realized_pnl_usd": { - "type": "number", - "description": "Only fire when realized PnL ≤ this value (USD)." - }, - "min_volume_usd": { - "type": "number", - "description": "Only fire when total trading volume ≥ this value (USD)." - }, - "max_volume_usd": { - "type": "number", - "description": "Only fire when total trading volume ≤ this value (USD)." - }, - "min_buy_usd": { - "type": "number", - "description": "Only fire when buy volume ≥ this value (USD)." - }, - "min_sell_volume_usd": { - "type": "number", - "description": "Only fire when sell volume ≥ this value (USD)." - }, - "min_win_rate": { - "type": "number", - "minimum": 0.0, - "maximum": 100.0, - "description": "Only fire when market win rate ≥ this percentage (0.0–100.0)." - }, - "min_markets_traded": { - "type": "integer", - "format": "int64", - "description": "Only fire when the trader has traded in ≥ this many markets." - }, - "timeframes": { - "type": "array", - "items": { - "type": "string", - "enum": [ - "1d", - "7d", - "30d", - "lifetime" - ] - }, - "description": "Restrict to these PnL windows. Empty = all windows." - } - } - }, - "TraderMarketPnlFilters": { - "type": "object", - "description": "Subscription filters for the `trader_market_pnl` event. All fields are optional.", - "properties": { - "traders": { - "type": "array", - "items": { - "type": "string" - }, - "maxItems": 500, - "description": "Track only these trader wallet addresses." - }, - "condition_ids": { - "type": "array", - "items": { - "type": "string" - }, - "maxItems": 500, - "description": "Restrict to these markets." - }, - "event_slugs": { - "type": "array", - "items": { - "type": "string" - }, - "maxItems": 500, - "description": "Restrict to markets in these events." - }, - "min_realized_pnl_usd": { - "type": "number", - "description": "Only fire when per-market realized PnL ≥ this value (USD)." - }, - "max_realized_pnl_usd": { - "type": "number", - "description": "Only fire when per-market realized PnL ≤ this value (USD)." - }, - "min_volume_usd": { - "type": "number", - "description": "Only fire when total volume (buy + sell + redemption + merge) ≥ this value (USD)." - }, - "max_volume_usd": { - "type": "number", - "description": "Only fire when total volume ≤ this value (USD)." - }, - "min_buy_usd": { - "type": "number", - "description": "Only fire when buy volume in the market ≥ this value (USD)." - }, - "min_sell_volume_usd": { - "type": "number", - "description": "Only fire when sell volume in the market ≥ this value (USD)." - }, - "timeframes": { - "type": "array", - "items": { - "type": "string", - "enum": [ - "1d", - "7d", - "30d", - "lifetime" - ] - }, - "description": "Restrict to these PnL windows." - }, - "exclude_shortterm_markets": { - "type": "boolean", - "description": "When `true`, suppress webhooks for short-term \"updown\" markets. Default: `false`." - } - } - }, - "TraderEventPnlFilters": { - "type": "object", - "description": "Subscription filters for the `trader_event_pnl` event. All fields are optional.", - "properties": { - "traders": { - "type": "array", - "items": { - "type": "string" - }, - "maxItems": 500, - "description": "Track only these trader wallet addresses." - }, - "event_slugs": { - "type": "array", - "items": { - "type": "string" - }, - "maxItems": 500, - "description": "Restrict to these events." - }, - "min_realized_pnl_usd": { - "type": "number", - "description": "Only fire when per-event realized PnL ≥ this value (USD)." - }, - "max_realized_pnl_usd": { - "type": "number", - "description": "Only fire when per-event realized PnL ≤ this value (USD)." - }, - "min_volume_usd": { - "type": "number", - "description": "Only fire when total event volume ≥ this value (USD)." - }, - "max_volume_usd": { - "type": "number", - "description": "Only fire when total event volume ≤ this value (USD)." - }, - "min_buy_usd": { - "type": "number", - "description": "Only fire when buy volume within the event ≥ this value (USD)." - }, - "min_sell_volume_usd": { - "type": "number", - "description": "Only fire when sell volume within the event ≥ this value (USD)." - }, - "min_markets_traded": { - "type": "integer", - "format": "int64", - "description": "Only fire when the trader has traded in ≥ this many markets within the event." - }, - "timeframes": { - "type": "array", - "items": { - "type": "string", - "enum": [ - "1d", - "7d", - "30d", - "lifetime" - ] - }, - "description": "Restrict to these PnL windows." - }, - "exclude_shortterm_markets": { - "type": "boolean", - "description": "When `true`, suppress webhooks for short-term \"updown\" markets. Default: `false`." - } - } - }, - "MarketMetricsFilters": { - "type": "object", - "description": "Subscription filters for the `condition_metrics` event. All fields are optional.", - "properties": { - "condition_ids": { - "type": "array", - "items": { - "type": "string" - }, - "maxItems": 500, - "description": "Restrict to these markets. Empty = all markets." - }, - "event_slugs": { - "type": "array", - "items": { - "type": "string" - }, - "maxItems": 500, - "description": "Restrict to markets in these events." - }, - "timeframes": { - "type": "array", - "items": { - "type": "string", - "enum": [ - "1m", - "5m", - "30m", - "1h", - "6h", - "24h", - "7d", - "30d" - ] - }, - "maxItems": 500, - "description": "Restrict to these aggregation windows. Empty = all windows." - }, - "min_volume_usd": { - "type": "number", - "description": "Only fire when volume ≥ this value (USD)." - }, - "max_volume_usd": { - "type": "number", - "description": "Only fire when volume ≤ this value (USD)." - }, - "min_txns": { - "type": "integer", - "format": "int64", - "description": "Only fire when transaction count ≥ this value." - }, - "min_unique_traders": { - "type": "integer", - "format": "int64", - "description": "Only fire when unique trader count ≥ this value." - }, - "min_fees": { - "type": "number", - "description": "Only fire when total fees ≥ this value (USD)." - } - } - }, - "EventMetricsFilters": { - "type": "object", - "description": "Subscription filters for the `event_metrics` event. All fields are optional.", - "properties": { - "event_slugs": { - "type": "array", - "items": { - "type": "string" - }, - "maxItems": 500, - "description": "Restrict to these events. Empty = all events." - }, - "timeframes": { - "type": "array", - "items": { - "type": "string", - "enum": [ - "1m", - "5m", - "30m", - "1h", - "6h", - "24h", - "7d", - "30d" - ] - }, - "maxItems": 500, - "description": "Restrict to these aggregation windows." - }, - "min_volume_usd": { - "type": "number", - "description": "Only fire when aggregated event volume ≥ this value (USD)." - }, - "max_volume_usd": { - "type": "number" - }, - "min_txns": { - "type": "integer", - "format": "int64" - }, - "min_unique_traders": { - "type": "integer", - "format": "int64" - }, - "min_fees": { - "type": "number" - }, - "exclude_shortterm_markets": { - "type": "boolean", - "description": "When `true`, suppress webhooks for short-term \"updown\" markets. Default: `false`." - } - } - }, - "PositionMetricsFilters": { - "type": "object", - "description": "Subscription filters for the `position_metrics` event. All fields are optional.", - "properties": { - "position_ids": { - "type": "array", - "items": { - "type": "string" - }, - "maxItems": 500, - "description": "Restrict to these outcome token IDs." - }, - "condition_ids": { - "type": "array", - "items": { - "type": "string" - }, - "maxItems": 500, - "description": "Restrict to positions within these markets." - }, - "outcomes": { - "type": "array", - "items": { - "type": "string" - }, - "maxItems": 500, - "description": "Restrict to positions with these outcome names (e.g. [\"Yes\", \"No\"])." - }, - "timeframes": { - "type": "array", - "items": { - "type": "string", - "enum": [ - "1m", - "5m", - "30m", - "1h", - "6h", - "24h", - "7d", - "30d" - ] - }, - "maxItems": 500, - "description": "Restrict to these aggregation windows." - }, - "min_volume_usd": { - "type": "number", - "description": "Only fire when position volume ≥ this value (USD)." - }, - "max_volume_usd": { - "type": "number" - }, - "min_buy_usd": { - "type": "number" - }, - "min_sell_volume_usd": { - "type": "number" - }, - "min_txns": { - "type": "integer", - "format": "int64" - }, - "min_unique_traders": { - "type": "integer", - "format": "int64" - }, - "min_price_change_pct": { - "type": "number", - "description": "Only fire when price change % ≥ this value." - }, - "min_probability_change_pct": { - "type": "number", - "description": "Only fire when probability change % ≥ this value." - }, - "min_fees": { - "type": "number" - } - } - }, - "MarketVolumeMilestoneFilters": { - "type": "object", - "description": "Subscription filters for the `market_volume_milestone` event.", - "required": [ - "timeframes" - ], - "properties": { - "timeframes": { - "type": "array", - "items": { - "type": "string", - "enum": [ - "1m", - "5m", - "30m", - "1h", - "6h", - "24h", - "7d", - "30d" - ] - }, - "minItems": 1, - "maxItems": 500, - "description": "**Required.** Aggregation windows to monitor (e.g. [\"1h\", \"24h\"])." - }, - "condition_ids": { - "type": "array", - "items": { - "type": "string" - }, - "maxItems": 500, - "description": "Restrict to these markets. Empty = all markets." - }, - "milestone_amounts": { - "type": "array", - "items": { - "type": "integer", - "format": "int64" - }, - "maxItems": 500, - "description": "Specific USD milestones to trigger on (e.g. [10000, 100000, 1000000]). Empty = all milestones." - } - } - }, - "EventVolumeMilestoneFilters": { - "type": "object", - "description": "Subscription filters for the `event_volume_milestone` event.", - "required": [ - "timeframes" - ], - "properties": { - "timeframes": { - "type": "array", - "items": { - "type": "string", - "enum": [ - "1m", - "5m", - "30m", - "1h", - "6h", - "24h", - "7d", - "30d" - ] - }, - "minItems": 1, - "maxItems": 500, - "description": "**Required.** Aggregation windows to monitor." - }, - "event_slugs": { - "type": "array", - "items": { - "type": "string" - }, - "maxItems": 500, - "description": "Restrict to these events." - }, - "milestone_amounts": { - "type": "array", - "items": { - "type": "integer", - "format": "int64" - }, - "maxItems": 500, - "description": "Specific USD milestones to trigger on." - }, - "exclude_shortterm_markets": { - "type": "boolean", - "description": "When `true`, suppress webhooks for short-term \"updown\" markets. Default: `false`." - } - } - }, - "PositionVolumeMilestoneFilters": { - "type": "object", - "description": "Subscription filters for the `position_volume_milestone` event.", - "required": [ - "timeframes" - ], - "properties": { - "timeframes": { - "type": "array", - "items": { - "type": "string", - "enum": [ - "1m", - "5m", - "30m", - "1h", - "6h", - "24h", - "7d", - "30d" - ] - }, - "minItems": 1, - "maxItems": 500, - "description": "**Required.** Aggregation windows to monitor." - }, - "position_ids": { - "type": "array", - "items": { - "type": "string" - }, - "maxItems": 500, - "description": "Restrict to these outcome token IDs." - }, - "condition_ids": { - "type": "array", - "items": { - "type": "string" - }, - "maxItems": 500, - "description": "Restrict to positions within these markets." - }, - "milestone_amounts": { - "type": "array", - "items": { - "type": "integer", - "format": "int64" - }, - "maxItems": 500, - "description": "Specific USD milestones to trigger on." - } - } - }, - "ProbabilitySpikeFilters": { - "type": "object", - "description": "Subscription filters for the `probability_spike` event.", - "properties": { - "position_ids": { - "type": "array", - "items": { - "type": "string" - }, - "maxItems": 500, - "description": "Restrict to specific outcome token IDs. Empty = all positions." - }, - "condition_ids": { - "type": "array", - "items": { - "type": "string" - }, - "maxItems": 500, - "description": "Restrict to specific market condition IDs. Empty = all markets." - }, - "event_slugs": { - "type": "array", - "items": { - "type": "string" - }, - "maxItems": 500, - "description": "Restrict to specific events. Empty = all events." - }, - "outcomes": { - "type": "array", - "items": { - "type": "string" - }, - "maxItems": 500, - "description": "Restrict to these outcome names (e.g. [\"Yes\", \"No\"])." - }, - "min_probability_change_pct": { - "type": "number", - "description": "Minimum probability percentage move to trigger (e.g. `10` for a 10% move)." - }, - "spike_direction": { - "type": "string", - "enum": [ - "up", - "down", - "both" - ], - "description": "`\"up\"` = probability rising only (default when omitted), `\"down\"` = falling only, `\"both\"` = either direction." - }, - "window_secs": { - "type": "integer", - "minimum": 1, - "maximum": 600, - "description": "Observation window in seconds. The first trade in each window sets the reference price; subsequent trades are compared to it. E.g. `60` detects moves that occur within 60 seconds." - }, - "exclude_shortterm_markets": { - "type": "boolean", - "description": "When `true`, suppress webhooks for short-term \"updown\" markets. Default: `false`." - } - } - }, - "PriceSpikeFilters": { - "type": "object", - "description": "Subscription filters for the `price_spike` event.", - "properties": { - "position_ids": { - "type": "array", - "items": { - "type": "string" - }, - "maxItems": 500, - "description": "Restrict to specific outcome token IDs. Empty = all positions." - }, - "condition_ids": { - "type": "array", - "items": { - "type": "string" - }, - "maxItems": 500, - "description": "Restrict to specific market condition IDs. Empty = all markets." - }, - "event_slugs": { - "type": "array", - "items": { - "type": "string" - }, - "maxItems": 500, - "description": "Restrict to specific events. Empty = all events." - }, - "outcomes": { - "type": "array", - "items": { - "type": "string" - }, - "maxItems": 500, - "description": "Restrict to these outcome names (e.g. [\"Yes\", \"No\"])." - }, - "min_price_change_pct": { - "type": "number", - "description": "Minimum price percentage move to trigger (e.g. `10` for a 10% move)." - }, - "spike_direction": { - "type": "string", - "enum": [ - "up", - "down", - "both" - ], - "description": "`\"up\"` = price rising only (default when omitted), `\"down\"` = falling only, `\"both\"` = either direction." - }, - "window_secs": { - "type": "integer", - "minimum": 1, - "maximum": 600, - "description": "Observation window in seconds. The first trade in each window sets the reference price; subsequent trades are compared to it. E.g. `60` detects moves that occur within 60 seconds." - }, - "exclude_shortterm_markets": { - "type": "boolean", - "description": "When `true`, suppress webhooks for short-term \"updown\" markets. Default: `false`." - } - } - }, - "MarketVolumeSpikeFilters": { - "type": "object", - "description": "Subscription filters for the `market_volume_spike` event. `spike_ratio` is required.", - "required": [ - "spike_ratio" - ], - "properties": { - "spike_ratio": { - "type": "number", - "exclusiveMinimum": 1.0, - "description": "**Required.** Multiplier threshold (must be > 1.0). Fires when current volume >= snapshot × ratio. The snapshot is set automatically on first data and resets after each fire." - }, - "window_secs": { - "type": "integer", - "minimum": 1, - "maximum": 600, - "description": "Force snapshot reset after this many seconds (max 600 / 10 minutes)." - }, - "condition_ids": { - "type": "array", - "items": { - "type": "string" - }, - "maxItems": 500, - "description": "Restrict to these markets. Empty = all markets." - }, - "timeframes": { - "type": "array", - "items": { - "type": "string", - "enum": [ - "1m", - "5m", - "30m", - "1h", - "6h", - "1d", - "24h", - "7d", - "30d" - ] - }, - "maxItems": 500, - "description": "Restrict to these aggregation windows. Empty = all windows." - } - } - }, - "EventVolumeSpikeFilters": { - "type": "object", - "description": "Subscription filters for the `event_volume_spike` event. `spike_ratio` is required.", - "required": [ - "spike_ratio" - ], - "properties": { - "spike_ratio": { - "type": "number", - "exclusiveMinimum": 1.0, - "description": "**Required.** Multiplier threshold (must be > 1.0). Fires when current volume >= snapshot × ratio." - }, - "window_secs": { - "type": "integer", - "minimum": 1, - "maximum": 600, - "description": "Force snapshot reset after this many seconds (max 600 / 10 minutes)." - }, - "event_slugs": { - "type": "array", - "items": { - "type": "string" - }, - "maxItems": 500, - "description": "Restrict to these events." - }, - "timeframes": { - "type": "array", - "items": { - "type": "string", - "enum": [ - "1m", - "5m", - "30m", - "1h", - "6h", - "1d", - "24h", - "7d", - "30d" - ] - }, - "maxItems": 500, - "description": "Restrict to these aggregation windows." - }, - "exclude_shortterm_markets": { - "type": "boolean", - "description": "When `true`, suppress webhooks for short-term \"updown\" markets. Default: `false`." - } - } - }, - "WsAlertEventType": { - "type": "string", - "description": "All alert event types supported by both HTTP webhooks and the alerts WebSocket.", - "enum": [ - "trader_first_trade", - "trader_new_market", - "trader_whale_trade", - "trader_new_trade", - "trader_global_pnl", - "trader_market_pnl", - "trader_event_pnl", - "condition_metrics", - "event_metrics", - "position_metrics", - "market_volume_milestone", - "event_volume_milestone", - "position_volume_milestone", - "probability_spike", - "price_spike", - "market_volume_spike", - "event_volume_spike", - "position_volume_spike", - "close_to_bond", - "market_created", - "asset_price_tick", - "asset_price_window_update" - ] - }, - "WsAlertSubscribedResponse": { - "type": "object", - "required": [ - "op", - "event", - "subscription_id" - ], - "description": "Server acknowledgement for a successful alert subscription.", - "properties": { - "op": { - "type": "string", - "enum": [ - "subscribed" - ] - }, - "event": { - "$ref": "#/components/schemas/WsAlertEventType" - }, - "subscription_id": { - "type": "string", - "format": "uuid" - } - } - }, - "WsAlertUnsubscribedResponse": { - "type": "object", - "required": [ - "op", - "event" - ], - "description": "Server acknowledgement for a successful alert unsubscription.", - "properties": { - "op": { - "type": "string", - "enum": [ - "unsubscribed" - ] - }, - "event": { - "$ref": "#/components/schemas/WsAlertEventType" - } - } - }, - "WsAlertErrorResponse": { - "type": "object", - "required": [ - "error" - ], - "description": "Error returned by the alerts WebSocket when a message is invalid or a subscription request fails.", - "properties": { - "error": { - "type": "string" - } - } - }, - "WsAlertTraderFirstTradeSubscribeMessage": { - "allOf": [ - { - "type": "object", - "description": "Subscribe to `trader_first_trade` alerts. Fired when a tracked trader executes their first trade on Polymarket", - "required": [ - "op", - "event" - ], - "properties": { - "op": { - "type": "string", - "enum": [ - "subscribe" - ] - }, - "event": { - "type": "string", - "enum": [ - "trader_first_trade" - ] - } - }, - "example": { - "op": "subscribe", - "event": "trader_first_trade", - "wallet_addresses": [ - "0x0000000000000000000000000000000000000000" - ], - "min_usd_value": 10000.0, - "min_probability": 0.95, - "max_probability": 0.05, - "condition_ids": [ - "0x0000000000000000000000000000000000000000000000000000000000000000" - ], - "event_slugs": [ - "example-event" - ], - "exclude_shortterm_markets": true - } - }, - { - "$ref": "#/components/schemas/TraderFirstTradeFilters" - } - ] - }, - "WsAlertTraderFirstTradeUnsubscribeMessage": { - "allOf": [ - { - "type": "object", - "description": "Unsubscribe from `trader_first_trade` alerts. The filter fields must match the original subscription exactly.", - "required": [ - "op", - "event" - ], - "properties": { - "op": { - "type": "string", - "enum": [ - "unsubscribe" - ] - }, - "event": { - "type": "string", - "enum": [ - "trader_first_trade" - ] - } - }, - "example": { - "op": "unsubscribe", - "event": "trader_first_trade", - "wallet_addresses": [ - "0x0000000000000000000000000000000000000000" - ], - "min_usd_value": 10000.0, - "min_probability": 0.95, - "max_probability": 0.05, - "condition_ids": [ - "0x0000000000000000000000000000000000000000000000000000000000000000" - ], - "event_slugs": [ - "example-event" - ], - "exclude_shortterm_markets": true - } - }, - { - "$ref": "#/components/schemas/TraderFirstTradeFilters" - } - ] - }, - "WsAlertTraderFirstTradeEvent": { - "type": "object", - "required": [ - "event", - "timestamp", - "data" - ], - "description": "Pushed `trader_first_trade` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", - "properties": { - "event": { - "type": "string", - "enum": [ - "trader_first_trade" - ] - }, - "timestamp": { - "type": "integer", - "format": "int64", - "description": "Unix timestamp in milliseconds" - }, - "data": { - "$ref": "#/components/schemas/FirstTradePayload" - } - }, - "example": { - "event": "trader_first_trade", - "timestamp": 1743500000000, - "data": { - "trader": "0x0000000000000000000000000000000000000000", - "taker": "0x0000000000000000000000000000000000000000", - "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", - "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", - "outcome": "Yes", - "outcome_index": 0, - "question": "Will this test webhook fire correctly?", - "market_slug": "test-market-0000000000", - "event_slug": "test-event-0000000000", - "trade_id": "00000000-0000-0000-0000-000000000000", - "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "block": 0, - "confirmed_at": 1700000000, - "amount_usd": 125.0, - "shares_amount": 250.0, - "fee": 0.125, - "side": "Buy", - "price": 0.5, - "exchange": "polymarket", - "trade_type": "OrderFilled" - } - } - }, - "WsAlertTraderNewMarketSubscribeMessage": { - "allOf": [ - { - "type": "object", - "description": "Subscribe to `trader_new_market` alerts. Fired when a trader places their first trade in a specific market/condition (fires once per trader+market pair)", - "required": [ - "op", - "event" - ], - "properties": { - "op": { - "type": "string", - "enum": [ - "subscribe" - ] - }, - "event": { - "type": "string", - "enum": [ - "trader_new_market" - ] - } - }, - "example": { - "op": "subscribe", - "event": "trader_new_market", - "wallet_addresses": [ - "0x0000000000000000000000000000000000000000" - ], - "condition_ids": [ - "0x0000000000000000000000000000000000000000000000000000000000000000" - ], - "event_slugs": [ - "example-event" - ], - "min_usd_value": 10000.0, - "min_probability": 0.95, - "max_probability": 0.05, - "exclude_shortterm_markets": true - } - }, - { - "$ref": "#/components/schemas/TraderNewMarketFilters" - } - ] - }, - "WsAlertTraderNewMarketUnsubscribeMessage": { - "allOf": [ - { - "type": "object", - "description": "Unsubscribe from `trader_new_market` alerts. The filter fields must match the original subscription exactly.", - "required": [ - "op", - "event" - ], - "properties": { - "op": { - "type": "string", - "enum": [ - "unsubscribe" - ] - }, - "event": { - "type": "string", - "enum": [ - "trader_new_market" - ] - } - }, - "example": { - "op": "unsubscribe", - "event": "trader_new_market", - "wallet_addresses": [ - "0x0000000000000000000000000000000000000000" - ], - "condition_ids": [ - "0x0000000000000000000000000000000000000000000000000000000000000000" - ], - "event_slugs": [ - "example-event" - ], - "min_usd_value": 10000.0, - "min_probability": 0.95, - "max_probability": 0.05, - "exclude_shortterm_markets": true - } - }, - { - "$ref": "#/components/schemas/TraderNewMarketFilters" - } - ] - }, - "WsAlertTraderNewMarketEvent": { - "type": "object", - "required": [ - "event", - "timestamp", - "data" - ], - "description": "Pushed `trader_new_market` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", - "properties": { - "event": { - "type": "string", - "enum": [ - "trader_new_market" - ] - }, - "timestamp": { - "type": "integer", - "format": "int64", - "description": "Unix timestamp in milliseconds" - }, - "data": { - "$ref": "#/components/schemas/NewMarketPayload" - } - }, - "example": { - "event": "trader_new_market", - "timestamp": 1743500000000, - "data": { - "trader": "0x0000000000000000000000000000000000000000", - "taker": "0x0000000000000000000000000000000000000000", - "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", - "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", - "outcome": "Yes", - "outcome_index": 0, - "question": "Will this test webhook fire correctly?", - "market_slug": "test-market-0000000000", - "event_slug": "test-event-0000000000", - "trade_id": "00000000-0000-0000-0000-000000000000", - "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "block": 0, - "confirmed_at": 1700000000, - "amount_usd": 125.0, - "shares_amount": 250.0, - "fee": 0.125, - "side": "Buy", - "price": 0.5, - "probability": 0.5, - "exchange": "polymarket", - "trade_type": "OrderFilled" - } - } - }, - "WsAlertTraderWhaleTradeSubscribeMessage": { - "allOf": [ - { - "type": "object", - "description": "Subscribe to `trader_whale_trade` alerts. Fired when a trade meets the configured criteria. Use `min_usd_value` to filter by minimum trade size (optional, defaults to 0 — matches all trades), and `min_probability`/`max_probability` to restrict to a probability range.", - "required": [ - "op", - "event" - ], - "properties": { - "op": { - "type": "string", - "enum": [ - "subscribe" - ] - }, - "event": { - "type": "string", - "enum": [ - "trader_whale_trade" - ] - } - }, - "example": { - "op": "subscribe", - "event": "trader_whale_trade", - "wallet_addresses": [ - "0x0000000000000000000000000000000000000000" - ], - "min_usd_value": 10000.0, - "min_probability": 0.95, - "max_probability": 0.05, - "condition_ids": [ - "0x0000000000000000000000000000000000000000000000000000000000000000" - ], - "event_slugs": [ - "example-event" - ], - "exclude_shortterm_markets": true - } - }, - { - "$ref": "#/components/schemas/TraderWhaleTradeFilters" - } - ] - }, - "WsAlertTraderWhaleTradeUnsubscribeMessage": { - "allOf": [ - { - "type": "object", - "description": "Unsubscribe from `trader_whale_trade` alerts. The filter fields must match the original subscription exactly.", - "required": [ - "op", - "event" - ], - "properties": { - "op": { - "type": "string", - "enum": [ - "unsubscribe" - ] - }, - "event": { - "type": "string", - "enum": [ - "trader_whale_trade" - ] - } - }, - "example": { - "op": "unsubscribe", - "event": "trader_whale_trade", - "wallet_addresses": [ - "0x0000000000000000000000000000000000000000" - ], - "min_usd_value": 10000.0, - "min_probability": 0.95, - "max_probability": 0.05, - "condition_ids": [ - "0x0000000000000000000000000000000000000000000000000000000000000000" - ], - "event_slugs": [ - "example-event" - ], - "exclude_shortterm_markets": true - } - }, - { - "$ref": "#/components/schemas/TraderWhaleTradeFilters" - } - ] - }, - "WsAlertTraderWhaleTradeEvent": { - "type": "object", - "required": [ - "event", - "timestamp", - "data" - ], - "description": "Pushed `trader_whale_trade` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", - "properties": { - "event": { - "type": "string", - "enum": [ - "trader_whale_trade" - ] - }, - "timestamp": { - "type": "integer", - "format": "int64", - "description": "Unix timestamp in milliseconds" - }, - "data": { - "$ref": "#/components/schemas/WhaleTradePayload" - } - }, - "example": { - "event": "trader_whale_trade", - "timestamp": 1743500000000, - "data": { - "trader": "0x0000000000000000000000000000000000000000", - "taker": "0x0000000000000000000000000000000000000000", - "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", - "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", - "outcome": "Yes", - "outcome_index": 0, - "question": "Will this test webhook fire correctly?", - "market_slug": "test-market-0000000000", - "event_slug": "test-event-0000000000", - "trade_id": "00000000-0000-0000-0000-000000000000", - "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "block": 0, - "confirmed_at": 1700000000, - "amount_usd": 125.0, - "shares_amount": 250.0, - "fee": 0.125, - "side": "Buy", - "price": 0.5, - "probability": 0.5, - "exchange": "polymarket", - "trade_type": "OrderFilled" - } - } - }, - "WsAlertTraderNewTradeSubscribeMessage": { - "allOf": [ - { - "type": "object", - "description": "Subscribe to `trader_new_trade` alerts. Fired on every order-filled trade. Use `wallet_addresses` to watch specific traders, `min_usd_value` to filter by size, and `min_probability`/`max_probability` to restrict to a probability range.", - "required": [ - "op", - "event" - ], - "properties": { - "op": { - "type": "string", - "enum": [ - "subscribe" - ] - }, - "event": { - "type": "string", - "enum": [ - "trader_new_trade" - ] - } - }, - "example": { - "op": "subscribe", - "event": "trader_new_trade", - "wallet_addresses": [ - "0x0000000000000000000000000000000000000000" - ], - "min_usd_value": 10000.0, - "min_probability": 0.95, - "max_probability": 0.05, - "condition_ids": [ - "0x0000000000000000000000000000000000000000000000000000000000000000" - ], - "event_slugs": [ - "example-event" - ], - "exclude_shortterm_markets": true - } - }, - { - "$ref": "#/components/schemas/TraderNewTradeFilters" - } - ] - }, - "WsAlertTraderNewTradeUnsubscribeMessage": { - "allOf": [ - { - "type": "object", - "description": "Unsubscribe from `trader_new_trade` alerts. The filter fields must match the original subscription exactly.", - "required": [ - "op", - "event" - ], - "properties": { - "op": { - "type": "string", - "enum": [ - "unsubscribe" - ] - }, - "event": { - "type": "string", - "enum": [ - "trader_new_trade" - ] - } - }, - "example": { - "op": "unsubscribe", - "event": "trader_new_trade", - "wallet_addresses": [ - "0x0000000000000000000000000000000000000000" - ], - "min_usd_value": 10000.0, - "min_probability": 0.95, - "max_probability": 0.05, - "condition_ids": [ - "0x0000000000000000000000000000000000000000000000000000000000000000" - ], - "event_slugs": [ - "example-event" - ], - "exclude_shortterm_markets": true - } - }, - { - "$ref": "#/components/schemas/TraderNewTradeFilters" - } - ] - }, - "WsAlertTraderNewTradeEvent": { - "type": "object", - "required": [ - "event", - "timestamp", - "data" - ], - "description": "Pushed `trader_new_trade` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", - "properties": { - "event": { - "type": "string", - "enum": [ - "trader_new_trade" - ] - }, - "timestamp": { - "type": "integer", - "format": "int64", - "description": "Unix timestamp in milliseconds" - }, - "data": { - "$ref": "#/components/schemas/NewTradePayload" - } - }, - "example": { - "event": "trader_new_trade", - "timestamp": 1743500000000, - "data": { - "trader": "0x0000000000000000000000000000000000000000", - "taker": "0x0000000000000000000000000000000000000000", - "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", - "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", - "outcome": "Yes", - "outcome_index": 0, - "question": "Will this test webhook fire correctly?", - "market_slug": "test-market-0000000000", - "event_slug": "test-event-0000000000", - "trade_id": "00000000-0000-0000-0000-000000000000", - "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "block": 0, - "confirmed_at": 1700000000, - "amount_usd": 25.0, - "shares_amount": 50.0, - "fee": 0.025, - "side": "Buy", - "price": 0.5, - "probability": 0.5, - "exchange": "polymarket", - "trade_type": "OrderFilled" - } - } - }, - "WsAlertTraderGlobalPnlSubscribeMessage": { - "allOf": [ - { - "type": "object", - "description": "Subscribe to `trader_global_pnl` alerts. Fired when a trader's global PnL crosses a configured threshold", - "required": [ - "op", - "event" - ], - "properties": { - "op": { - "type": "string", - "enum": [ - "subscribe" - ] - }, - "event": { - "type": "string", - "enum": [ - "trader_global_pnl" - ] - } - }, - "example": { - "op": "subscribe", - "event": "trader_global_pnl", - "traders": [ - "0x0000000000000000000000000000000000000000" - ], - "min_realized_pnl_usd": 1000.0, - "max_realized_pnl_usd": 5000.0, - "min_volume_usd": 10000.0, - "max_volume_usd": 100000.0, - "min_buy_usd": 5000.0, - "min_sell_volume_usd": 2500.0, - "min_win_rate": 60.0, - "min_markets_traded": 5, - "timeframes": [ - "1h" - ] - } - }, - { - "$ref": "#/components/schemas/TraderGlobalPnlFilters" - } - ] - }, - "WsAlertTraderGlobalPnlUnsubscribeMessage": { - "allOf": [ - { - "type": "object", - "description": "Unsubscribe from `trader_global_pnl` alerts. The filter fields must match the original subscription exactly.", - "required": [ - "op", - "event" - ], - "properties": { - "op": { - "type": "string", - "enum": [ - "unsubscribe" - ] - }, - "event": { - "type": "string", - "enum": [ - "trader_global_pnl" - ] - } - }, - "example": { - "op": "unsubscribe", - "event": "trader_global_pnl", - "traders": [ - "0x0000000000000000000000000000000000000000" - ], - "min_realized_pnl_usd": 1000.0, - "max_realized_pnl_usd": 5000.0, - "min_volume_usd": 10000.0, - "max_volume_usd": 100000.0, - "min_buy_usd": 5000.0, - "min_sell_volume_usd": 2500.0, - "min_win_rate": 60.0, - "min_markets_traded": 5, - "timeframes": [ - "1h" - ] - } - }, - { - "$ref": "#/components/schemas/TraderGlobalPnlFilters" - } - ] - }, - "WsAlertTraderGlobalPnlEvent": { - "type": "object", - "required": [ - "event", - "timestamp", - "data" - ], - "description": "Pushed `trader_global_pnl` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", - "properties": { - "event": { - "type": "string", - "enum": [ - "trader_global_pnl" - ] - }, - "timestamp": { - "type": "integer", - "format": "int64", - "description": "Unix timestamp in milliseconds" - }, - "data": { - "$ref": "#/components/schemas/GlobalPnlPayload" - } - }, - "example": { - "event": "trader_global_pnl", - "timestamp": 1743500000000, - "data": { - "trader": "0x0000000000000000000000000000000000000000", - "timeframe": "7d", - "realized_pnl_usd": 250.0, - "events_traded": 3, - "markets_traded": 5, - "total_buys": 12, - "total_sells": 8, - "total_redemptions": 1, - "total_merges": 0, - "total_volume_usd": 1500.0, - "buy_volume_usd": 900.0, - "sell_volume_usd": 600.0, - "redemption_volume_usd": 50.0, - "merge_volume_usd": 0.0, - "markets_won": 3, - "markets_lost": 2, - "market_win_rate_pct": 60.0, - "avg_pnl_per_market": 50.0, - "avg_pnl_per_trade": 12.5, - "avg_hold_time_seconds": 86400.0, - "total_fees": 7.5, - "best_trade_pnl_usd": 180.0, - "best_trade_condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", - "first_trade_at": 1700000000, - "last_trade_at": 1700000000 - } - } - }, - "WsAlertTraderMarketPnlSubscribeMessage": { - "allOf": [ - { - "type": "object", - "description": "Subscribe to `trader_market_pnl` alerts. Fired when a trader's market-level PnL crosses a configured threshold", - "required": [ - "op", - "event" - ], - "properties": { - "op": { - "type": "string", - "enum": [ - "subscribe" - ] - }, - "event": { - "type": "string", - "enum": [ - "trader_market_pnl" - ] - } - }, - "example": { - "op": "subscribe", - "event": "trader_market_pnl", - "traders": [ - "0x0000000000000000000000000000000000000000" - ], - "condition_ids": [ - "0x0000000000000000000000000000000000000000000000000000000000000000" - ], - "event_slugs": [ - "example-event" - ], - "min_realized_pnl_usd": 1000.0, - "max_realized_pnl_usd": 5000.0, - "min_volume_usd": 10000.0, - "max_volume_usd": 100000.0, - "min_buy_usd": 5000.0, - "min_sell_volume_usd": 2500.0, - "timeframes": [ - "1h" - ], - "exclude_shortterm_markets": true - } - }, - { - "$ref": "#/components/schemas/TraderMarketPnlFilters" - } - ] - }, - "WsAlertTraderMarketPnlUnsubscribeMessage": { - "allOf": [ - { - "type": "object", - "description": "Unsubscribe from `trader_market_pnl` alerts. The filter fields must match the original subscription exactly.", - "required": [ - "op", - "event" - ], - "properties": { - "op": { - "type": "string", - "enum": [ - "unsubscribe" - ] - }, - "event": { - "type": "string", - "enum": [ - "trader_market_pnl" - ] - } - }, - "example": { - "op": "unsubscribe", - "event": "trader_market_pnl", - "traders": [ - "0x0000000000000000000000000000000000000000" - ], - "condition_ids": [ - "0x0000000000000000000000000000000000000000000000000000000000000000" - ], - "event_slugs": [ - "example-event" - ], - "min_realized_pnl_usd": 1000.0, - "max_realized_pnl_usd": 5000.0, - "min_volume_usd": 10000.0, - "max_volume_usd": 100000.0, - "min_buy_usd": 5000.0, - "min_sell_volume_usd": 2500.0, - "timeframes": [ - "1h" - ], - "exclude_shortterm_markets": true - } - }, - { - "$ref": "#/components/schemas/TraderMarketPnlFilters" - } - ] - }, - "WsAlertTraderMarketPnlEvent": { - "type": "object", - "required": [ - "event", - "timestamp", - "data" - ], - "description": "Pushed `trader_market_pnl` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", - "properties": { - "event": { - "type": "string", - "enum": [ - "trader_market_pnl" - ] - }, - "timestamp": { - "type": "integer", - "format": "int64", - "description": "Unix timestamp in milliseconds" - }, - "data": { - "$ref": "#/components/schemas/MarketPnlPayload" - } - }, - "example": { - "event": "trader_market_pnl", - "timestamp": 1743500000000, - "data": { - "trader": "0x0000000000000000000000000000000000000000", - "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", - "event_slug": "test-event-0000000000", - "timeframe": "7d", - "outcomes_traded": 2, - "total_buys": 4, - "total_sells": 3, - "total_redemptions": 1, - "total_merges": 0, - "buy_usd": 300.0, - "sell_usd": 200.0, - "redemption_usd": 50.0, - "merge_usd": 0.0, - "realized_pnl_usd": 100.0, - "winning_outcomes": 1, - "total_fees": 2.5, - "first_trade_at": 1700000000, - "last_trade_at": 1700000000 - } - } - }, - "WsAlertTraderEventPnlSubscribeMessage": { - "allOf": [ - { - "type": "object", - "description": "Subscribe to `trader_event_pnl` alerts. Fired when a trader's event-level PnL crosses a configured threshold", - "required": [ - "op", - "event" - ], - "properties": { - "op": { - "type": "string", - "enum": [ - "subscribe" - ] - }, - "event": { - "type": "string", - "enum": [ - "trader_event_pnl" - ] - } - }, - "example": { - "op": "subscribe", - "event": "trader_event_pnl", - "traders": [ - "0x0000000000000000000000000000000000000000" - ], - "event_slugs": [ - "example-event" - ], - "min_realized_pnl_usd": 1000.0, - "max_realized_pnl_usd": 5000.0, - "min_volume_usd": 10000.0, - "max_volume_usd": 100000.0, - "min_buy_usd": 5000.0, - "min_sell_volume_usd": 2500.0, - "min_markets_traded": 5, - "timeframes": [ - "1h" - ], - "exclude_shortterm_markets": true - } - }, - { - "$ref": "#/components/schemas/TraderEventPnlFilters" - } - ] - }, - "WsAlertTraderEventPnlUnsubscribeMessage": { - "allOf": [ - { - "type": "object", - "description": "Unsubscribe from `trader_event_pnl` alerts. The filter fields must match the original subscription exactly.", - "required": [ - "op", - "event" - ], - "properties": { - "op": { - "type": "string", - "enum": [ - "unsubscribe" - ] - }, - "event": { - "type": "string", - "enum": [ - "trader_event_pnl" - ] - } - }, - "example": { - "op": "unsubscribe", - "event": "trader_event_pnl", - "traders": [ - "0x0000000000000000000000000000000000000000" - ], - "event_slugs": [ - "example-event" - ], - "min_realized_pnl_usd": 1000.0, - "max_realized_pnl_usd": 5000.0, - "min_volume_usd": 10000.0, - "max_volume_usd": 100000.0, - "min_buy_usd": 5000.0, - "min_sell_volume_usd": 2500.0, - "min_markets_traded": 5, - "timeframes": [ - "1h" - ], - "exclude_shortterm_markets": true - } - }, - { - "$ref": "#/components/schemas/TraderEventPnlFilters" - } - ] - }, - "WsAlertTraderEventPnlEvent": { - "type": "object", - "required": [ - "event", - "timestamp", - "data" - ], - "description": "Pushed `trader_event_pnl` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", - "properties": { - "event": { - "type": "string", - "enum": [ - "trader_event_pnl" - ] - }, - "timestamp": { - "type": "integer", - "format": "int64", - "description": "Unix timestamp in milliseconds" - }, - "data": { - "$ref": "#/components/schemas/EventPnlPayload" - } - }, - "example": { - "event": "trader_event_pnl", - "timestamp": 1743500000000, - "data": { - "trader": "0x0000000000000000000000000000000000000000", - "event_slug": "test-event-0000000000", - "timeframe": "7d", - "markets_traded": 2, - "outcomes_traded": 3, - "total_buys": 6, - "total_sells": 4, - "total_redemptions": 1, - "total_merges": 0, - "total_volume_usd": 800.0, - "buy_usd": 480.0, - "sell_usd": 320.0, - "redemption_usd": 50.0, - "merge_usd": 0.0, - "realized_pnl_usd": 150.0, - "winning_markets": 1, - "losing_markets": 1, - "total_fees": 4.0, - "first_trade_at": 1700000000, - "last_trade_at": 1700000000 - } - } - }, - "WsAlertConditionMetricsSubscribeMessage": { - "allOf": [ - { - "type": "object", - "description": "Subscribe to `condition_metrics` alerts. Fired when a market's volume or transaction metrics cross a configured threshold. Use `timeframes` to restrict to specific windows (valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`).", - "required": [ - "op", - "event" - ], - "properties": { - "op": { - "type": "string", - "enum": [ - "subscribe" - ] - }, - "event": { - "type": "string", - "enum": [ - "condition_metrics" - ] - } - }, - "example": { - "op": "subscribe", - "event": "condition_metrics", - "condition_ids": [ - "0x0000000000000000000000000000000000000000000000000000000000000000" - ], - "min_volume_usd": 10000.0, - "max_volume_usd": 100000.0, - "min_fees": 100.0, - "min_txns": 10, - "min_unique_traders": 10, - "timeframes": [ - "1h" - ] - } - }, - { - "$ref": "#/components/schemas/MarketMetricsFilters" - } - ] - }, - "WsAlertConditionMetricsUnsubscribeMessage": { - "allOf": [ - { - "type": "object", - "description": "Unsubscribe from `condition_metrics` alerts. The filter fields must match the original subscription exactly.", - "required": [ - "op", - "event" - ], - "properties": { - "op": { - "type": "string", - "enum": [ - "unsubscribe" - ] - }, - "event": { - "type": "string", - "enum": [ - "condition_metrics" - ] - } - }, - "example": { - "op": "unsubscribe", - "event": "condition_metrics", - "condition_ids": [ - "0x0000000000000000000000000000000000000000000000000000000000000000" - ], - "min_volume_usd": 10000.0, - "max_volume_usd": 100000.0, - "min_fees": 100.0, - "min_txns": 10, - "min_unique_traders": 10, - "timeframes": [ - "1h" - ] - } - }, - { - "$ref": "#/components/schemas/MarketMetricsFilters" - } - ] - }, - "WsAlertConditionMetricsEvent": { - "type": "object", - "required": [ - "event", - "timestamp", - "data" - ], - "description": "Pushed `condition_metrics` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", - "properties": { - "event": { - "type": "string", - "enum": [ - "condition_metrics" - ] - }, - "timestamp": { - "type": "integer", - "format": "int64", - "description": "Unix timestamp in milliseconds" - }, - "data": { - "$ref": "#/components/schemas/ConditionMetricsPayload" - } - }, - "example": { - "event": "condition_metrics", - "timestamp": 1743500000000, - "data": { - "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", - "timeframe": "1h", - "volume_usd": 50000.0, - "fees": 250.0, - "txns": 320, - "unique_traders": 85 - } - } - }, - "WsAlertEventMetricsSubscribeMessage": { - "allOf": [ - { - "type": "object", - "description": "Subscribe to `event_metrics` alerts. Fired when an event's volume or transaction metrics cross a configured threshold. Use `timeframes` to restrict to specific windows (valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`).", - "required": [ - "op", - "event" - ], - "properties": { - "op": { - "type": "string", - "enum": [ - "subscribe" - ] - }, - "event": { - "type": "string", - "enum": [ - "event_metrics" - ] - } - }, - "example": { - "op": "subscribe", - "event": "event_metrics", - "event_slugs": [ - "example-event" - ], - "min_volume_usd": 10000.0, - "max_volume_usd": 100000.0, - "min_fees": 100.0, - "min_txns": 10, - "min_unique_traders": 10, - "timeframes": [ - "1h" - ], - "exclude_shortterm_markets": true - } - }, - { - "$ref": "#/components/schemas/EventMetricsFilters" - } - ] - }, - "WsAlertEventMetricsUnsubscribeMessage": { - "allOf": [ - { - "type": "object", - "description": "Unsubscribe from `event_metrics` alerts. The filter fields must match the original subscription exactly.", - "required": [ - "op", - "event" - ], - "properties": { - "op": { - "type": "string", - "enum": [ - "unsubscribe" - ] - }, - "event": { - "type": "string", - "enum": [ - "event_metrics" - ] - } - }, - "example": { - "op": "unsubscribe", - "event": "event_metrics", - "event_slugs": [ - "example-event" - ], - "min_volume_usd": 10000.0, - "max_volume_usd": 100000.0, - "min_fees": 100.0, - "min_txns": 10, - "min_unique_traders": 10, - "timeframes": [ - "1h" - ], - "exclude_shortterm_markets": true - } - }, - { - "$ref": "#/components/schemas/EventMetricsFilters" - } - ] - }, - "WsAlertEventMetricsEvent": { - "type": "object", - "required": [ - "event", - "timestamp", - "data" - ], - "description": "Pushed `event_metrics` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", - "properties": { - "event": { - "type": "string", - "enum": [ - "event_metrics" - ] - }, - "timestamp": { - "type": "integer", - "format": "int64", - "description": "Unix timestamp in milliseconds" - }, - "data": { - "$ref": "#/components/schemas/EventMetricsPayload" - } - }, - "example": { - "event": "event_metrics", - "timestamp": 1743500000000, - "data": { - "event_slug": "test-event-0000000000", - "timeframe": "1h", - "volume_usd": 120000.0, - "fees": 600.0, - "txns": 740, - "unique_traders": 210 - } - } - }, - "WsAlertPositionMetricsSubscribeMessage": { - "allOf": [ - { - "type": "object", - "description": "Subscribe to `position_metrics` alerts. Fired when a position's volume or transaction metrics cross a configured threshold. Use `timeframes` to restrict to specific windows (valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`).", - "required": [ - "op", - "event" - ], - "properties": { - "op": { - "type": "string", - "enum": [ - "subscribe" - ] - }, - "event": { - "type": "string", - "enum": [ - "position_metrics" - ] - } - }, - "example": { - "op": "subscribe", - "event": "position_metrics", - "position_ids": [ - "452312848583266388373324160190187140051835877600158453279131187530910662656" - ], - "condition_ids": [ - "0x0000000000000000000000000000000000000000000000000000000000000000" - ], - "outcomes": [ - "Yes" - ], - "min_volume_usd": 10000.0, - "max_volume_usd": 100000.0, - "min_buy_usd": 5000.0, - "min_sell_volume_usd": 2500.0, - "min_fees": 100.0, - "min_txns": 10, - "min_price_change_pct": 10.0, - "min_probability_change_pct": 10.0, - "timeframes": [ - "1h" - ] - } - }, - { - "$ref": "#/components/schemas/PositionMetricsFilters" - } - ] - }, - "WsAlertPositionMetricsUnsubscribeMessage": { - "allOf": [ - { - "type": "object", - "description": "Unsubscribe from `position_metrics` alerts. The filter fields must match the original subscription exactly.", - "required": [ - "op", - "event" - ], - "properties": { - "op": { - "type": "string", - "enum": [ - "unsubscribe" - ] - }, - "event": { - "type": "string", - "enum": [ - "position_metrics" - ] - } - }, - "example": { - "op": "unsubscribe", - "event": "position_metrics", - "position_ids": [ - "452312848583266388373324160190187140051835877600158453279131187530910662656" - ], - "condition_ids": [ - "0x0000000000000000000000000000000000000000000000000000000000000000" - ], - "outcomes": [ - "Yes" - ], - "min_volume_usd": 10000.0, - "max_volume_usd": 100000.0, - "min_buy_usd": 5000.0, - "min_sell_volume_usd": 2500.0, - "min_fees": 100.0, - "min_txns": 10, - "min_price_change_pct": 10.0, - "min_probability_change_pct": 10.0, - "timeframes": [ - "1h" - ] - } - }, - { - "$ref": "#/components/schemas/PositionMetricsFilters" - } - ] - }, - "WsAlertPositionMetricsEvent": { - "type": "object", - "required": [ - "event", - "timestamp", - "data" - ], - "description": "Pushed `position_metrics` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", - "properties": { - "event": { - "type": "string", - "enum": [ - "position_metrics" - ] - }, - "timestamp": { - "type": "integer", - "format": "int64", - "description": "Unix timestamp in milliseconds" - }, - "data": { - "$ref": "#/components/schemas/PositionMetricsPayload" - } - }, - "example": { - "event": "position_metrics", - "timestamp": 1743500000000, - "data": { - "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", - "outcome": "Yes", - "outcome_index": 0, - "timeframe": "1h", - "volume_usd": 25000.0, - "buy_volume_usd": 15000.0, - "sell_volume_usd": 10000.0, - "fees": 125.0, - "txns": 160, - "buys": 95, - "sells": 65, - "unique_traders": 48, - "price_open": 0.48, - "price_close": 0.52, - "price_high": 0.55, - "price_low": 0.46, - "probability_open": 0.48, - "probability_close": 0.52, - "probability_high": 0.55, - "probability_low": 0.46 - } - } - }, - "WsAlertMarketVolumeMilestoneSubscribeMessage": { - "allOf": [ - { - "type": "object", - "description": "Subscribe to `market_volume_milestone` alerts. Fired when a market's trading volume crosses a milestone threshold in the specified timeframe. **`timeframes` is required** (e.g. `[\"1h\", \"24h\"]`) — valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`. Optional `milestone_amounts` restricts to specific USD thresholds (e.g. `[10000, 100000]`). Optional `condition_ids` restricts to specific markets.", - "required": [ - "op", - "event" - ], - "properties": { - "op": { - "type": "string", - "enum": [ - "subscribe" - ] - }, - "event": { - "type": "string", - "enum": [ - "market_volume_milestone" - ] - } - }, - "example": { - "op": "subscribe", - "event": "market_volume_milestone", - "condition_ids": [ - "0x0000000000000000000000000000000000000000000000000000000000000000" - ], - "timeframes": [ - "1h" - ], - "milestone_amounts": [ - 10000 - ] - } - }, - { - "$ref": "#/components/schemas/MarketVolumeMilestoneFilters" - } - ] - }, - "WsAlertMarketVolumeMilestoneUnsubscribeMessage": { - "allOf": [ - { - "type": "object", - "description": "Unsubscribe from `market_volume_milestone` alerts. The filter fields must match the original subscription exactly.", - "required": [ - "op", - "event" - ], - "properties": { - "op": { - "type": "string", - "enum": [ - "unsubscribe" - ] - }, - "event": { - "type": "string", - "enum": [ - "market_volume_milestone" - ] - } - }, - "example": { - "op": "unsubscribe", - "event": "market_volume_milestone", - "condition_ids": [ - "0x0000000000000000000000000000000000000000000000000000000000000000" - ], - "timeframes": [ - "1h" - ], - "milestone_amounts": [ - 10000 - ] - } - }, - { - "$ref": "#/components/schemas/MarketVolumeMilestoneFilters" - } - ] - }, - "WsAlertMarketVolumeMilestoneEvent": { - "type": "object", - "required": [ - "event", - "timestamp", - "data" - ], - "description": "Pushed `market_volume_milestone` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", - "properties": { - "event": { - "type": "string", - "enum": [ - "market_volume_milestone" - ] - }, - "timestamp": { - "type": "integer", - "format": "int64", - "description": "Unix timestamp in milliseconds" - }, - "data": { - "$ref": "#/components/schemas/VolumeMilestonePayload" - } - }, - "example": { - "event": "market_volume_milestone", - "timestamp": 1743500000000, - "data": { - "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", - "timeframe": "24h", - "milestone_usd": 100000.0, - "current_volume_usd": 100125.0, - "fees": 500.0, - "txns": 650 - } - } - }, - "WsAlertEventVolumeMilestoneSubscribeMessage": { - "allOf": [ - { - "type": "object", - "description": "Subscribe to `event_volume_milestone` alerts. Fired when an event's trading volume crosses a milestone threshold in the specified timeframe. **`timeframes` is required** (e.g. `[\"1h\", \"24h\"]`) — valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`. Optional `milestone_amounts` restricts to specific USD thresholds. Optional `event_slugs` restricts to specific events.", - "required": [ - "op", - "event" - ], - "properties": { - "op": { - "type": "string", - "enum": [ - "subscribe" - ] - }, - "event": { - "type": "string", - "enum": [ - "event_volume_milestone" - ] - } - }, - "example": { - "op": "subscribe", - "event": "event_volume_milestone", - "event_slugs": [ - "example-event" - ], - "timeframes": [ - "1h" - ], - "milestone_amounts": [ - 10000 - ], - "exclude_shortterm_markets": true - } - }, - { - "$ref": "#/components/schemas/EventVolumeMilestoneFilters" - } - ] - }, - "WsAlertEventVolumeMilestoneUnsubscribeMessage": { - "allOf": [ - { - "type": "object", - "description": "Unsubscribe from `event_volume_milestone` alerts. The filter fields must match the original subscription exactly.", - "required": [ - "op", - "event" - ], - "properties": { - "op": { - "type": "string", - "enum": [ - "unsubscribe" - ] - }, - "event": { - "type": "string", - "enum": [ - "event_volume_milestone" - ] - } - }, - "example": { - "op": "unsubscribe", - "event": "event_volume_milestone", - "event_slugs": [ - "example-event" - ], - "timeframes": [ - "1h" - ], - "milestone_amounts": [ - 10000 - ], - "exclude_shortterm_markets": true - } - }, - { - "$ref": "#/components/schemas/EventVolumeMilestoneFilters" - } - ] - }, - "WsAlertEventVolumeMilestoneEvent": { - "type": "object", - "required": [ - "event", - "timestamp", - "data" - ], - "description": "Pushed `event_volume_milestone` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", - "properties": { - "event": { - "type": "string", - "enum": [ - "event_volume_milestone" - ] - }, - "timestamp": { - "type": "integer", - "format": "int64", - "description": "Unix timestamp in milliseconds" - }, - "data": { - "$ref": "#/components/schemas/EventVolumeMilestonePayload" - } - }, - "example": { - "event": "event_volume_milestone", - "timestamp": 1743500000000, - "data": { - "event_slug": "test-event-0000000000", - "timeframe": "24h", - "milestone_usd": 500000.0, - "current_volume_usd": 500250.0, - "fees": 2500.0, - "txns": 3200 - } - } - }, - "WsAlertPositionVolumeMilestoneSubscribeMessage": { - "allOf": [ - { - "type": "object", - "description": "Subscribe to `position_volume_milestone` alerts. Fired when a position's trading volume crosses a milestone threshold in the specified timeframe. **`timeframes` is required** (e.g. `[\"1h\", \"24h\"]`) — valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `24h`, `7d`, `30d`. Optional `milestone_amounts` restricts to specific USD thresholds. Optional `position_ids` or `condition_ids` restrict to specific positions/markets.", - "required": [ - "op", - "event" - ], - "properties": { - "op": { - "type": "string", - "enum": [ - "subscribe" - ] - }, - "event": { - "type": "string", - "enum": [ - "position_volume_milestone" - ] - } - }, - "example": { - "op": "subscribe", - "event": "position_volume_milestone", - "position_ids": [ - "452312848583266388373324160190187140051835877600158453279131187530910662656" - ], - "condition_ids": [ - "0x0000000000000000000000000000000000000000000000000000000000000000" - ], - "outcomes": [ - "Yes" - ], - "timeframes": [ - "1h" - ], - "milestone_amounts": [ - 10000 - ] - } - }, - { - "$ref": "#/components/schemas/PositionVolumeMilestoneFilters" - } - ] - }, - "WsAlertPositionVolumeMilestoneUnsubscribeMessage": { - "allOf": [ - { - "type": "object", - "description": "Unsubscribe from `position_volume_milestone` alerts. The filter fields must match the original subscription exactly.", - "required": [ - "op", - "event" - ], - "properties": { - "op": { - "type": "string", - "enum": [ - "unsubscribe" - ] - }, - "event": { - "type": "string", - "enum": [ - "position_volume_milestone" - ] - } - }, - "example": { - "op": "unsubscribe", - "event": "position_volume_milestone", - "position_ids": [ - "452312848583266388373324160190187140051835877600158453279131187530910662656" - ], - "condition_ids": [ - "0x0000000000000000000000000000000000000000000000000000000000000000" - ], - "outcomes": [ - "Yes" - ], - "timeframes": [ - "1h" - ], - "milestone_amounts": [ - 10000 - ] - } - }, - { - "$ref": "#/components/schemas/PositionVolumeMilestoneFilters" - } - ] - }, - "WsAlertPositionVolumeMilestoneEvent": { - "type": "object", - "required": [ - "event", - "timestamp", - "data" - ], - "description": "Pushed `position_volume_milestone` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", - "properties": { - "event": { - "type": "string", - "enum": [ - "position_volume_milestone" - ] - }, - "timestamp": { - "type": "integer", - "format": "int64", - "description": "Unix timestamp in milliseconds" - }, - "data": { - "$ref": "#/components/schemas/PositionVolumeMilestonePayload" - } - }, - "example": { - "event": "position_volume_milestone", - "timestamp": 1743500000000, - "data": { - "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", - "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", - "outcome": "Yes", - "outcome_index": 0, - "timeframe": "24h", - "milestone_usd": 50000.0, - "current_volume_usd": 50125.0, - "buy_volume_usd": 30000.0, - "sell_volume_usd": 20000.0, - "fees": 250.0, - "txns": 320, - "buys": 190, - "sells": 130 - } - } - }, - "WsAlertProbabilitySpikeSubscribeMessage": { - "allOf": [ - { - "type": "object", - "description": "Subscribe to `probability_spike` alerts. Fired when a position's probability moves significantly. Use `min_probability_change_pct` to set the minimum move (e.g. `10` for 10%). Use `window_secs` to observe moves within a specific time window (e.g. `60` for 60 seconds). Use `spike_direction` (`\"up\"` | `\"down\"` | `\"both\"`) — defaults to `\"up\"` when not provided. Filter by `position_ids` or `outcomes` to narrow scope.", - "required": [ - "op", - "event" - ], - "properties": { - "op": { - "type": "string", - "enum": [ - "subscribe" - ] - }, - "event": { - "type": "string", - "enum": [ - "probability_spike" - ] - } - }, - "example": { - "op": "subscribe", - "event": "probability_spike", - "position_ids": [ - "452312848583266388373324160190187140051835877600158453279131187530910662656" - ], - "condition_ids": [ - "0x0000000000000000000000000000000000000000000000000000000000000000" - ], - "event_slugs": [ - "example-event" - ], - "outcomes": [ - "Yes" - ], - "min_probability_change_pct": 10.0, - "spike_direction": "up", - "window_secs": 60, - "exclude_shortterm_markets": true - } - }, - { - "$ref": "#/components/schemas/ProbabilitySpikeFilters" - } - ] - }, - "WsAlertProbabilitySpikeUnsubscribeMessage": { - "allOf": [ - { - "type": "object", - "description": "Unsubscribe from `probability_spike` alerts. The filter fields must match the original subscription exactly.", - "required": [ - "op", - "event" - ], - "properties": { - "op": { - "type": "string", - "enum": [ - "unsubscribe" - ] - }, - "event": { - "type": "string", - "enum": [ - "probability_spike" - ] - } - }, - "example": { - "op": "unsubscribe", - "event": "probability_spike", - "position_ids": [ - "452312848583266388373324160190187140051835877600158453279131187530910662656" - ], - "condition_ids": [ - "0x0000000000000000000000000000000000000000000000000000000000000000" - ], - "event_slugs": [ - "example-event" - ], - "outcomes": [ - "Yes" - ], - "min_probability_change_pct": 10.0, - "spike_direction": "up", - "window_secs": 60, - "exclude_shortterm_markets": true - } - }, - { - "$ref": "#/components/schemas/ProbabilitySpikeFilters" - } - ] - }, - "WsAlertProbabilitySpikeEvent": { - "type": "object", - "required": [ - "event", - "timestamp", - "data" - ], - "description": "Pushed `probability_spike` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", - "properties": { - "event": { - "type": "string", - "enum": [ - "probability_spike" - ] - }, - "timestamp": { - "type": "integer", - "format": "int64", - "description": "Unix timestamp in milliseconds" - }, - "data": { - "$ref": "#/components/schemas/ProbabilitySpikePayload" - } - }, - "example": { - "event": "probability_spike", - "timestamp": 1743500000000, - "data": { - "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", - "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", - "event_slug": "test-event-0000000000", - "outcome": "Yes", - "outcome_index": 0, - "previous_probability": 0.4, - "current_probability": 0.5, - "spike_direction": "up", - "spike_pct": 25.0 - } - } - }, - "WsAlertPriceSpikeSubscribeMessage": { - "allOf": [ - { - "type": "object", - "description": "Subscribe to `price_spike` alerts. Fired when a position's price moves significantly. Use `min_price_change_pct` to set the minimum move (e.g. `10` for 10%). Use `window_secs` to observe moves within a specific time window. Use `spike_direction` (`\"up\"` | `\"down\"` | `\"both\"`) — defaults to `\"up\"` when not provided. Filter by `position_ids` or `outcomes` to narrow scope.", - "required": [ - "op", - "event" - ], - "properties": { - "op": { - "type": "string", - "enum": [ - "subscribe" - ] - }, - "event": { - "type": "string", - "enum": [ - "price_spike" - ] - } - }, - "example": { - "op": "subscribe", - "event": "price_spike", - "position_ids": [ - "452312848583266388373324160190187140051835877600158453279131187530910662656" - ], - "condition_ids": [ - "0x0000000000000000000000000000000000000000000000000000000000000000" - ], - "event_slugs": [ - "example-event" - ], - "outcomes": [ - "Yes" - ], - "min_price_change_pct": 10.0, - "spike_direction": "up", - "window_secs": 60, - "exclude_shortterm_markets": true - } - }, - { - "$ref": "#/components/schemas/PriceSpikeFilters" - } - ] - }, - "WsAlertPriceSpikeUnsubscribeMessage": { - "allOf": [ - { - "type": "object", - "description": "Unsubscribe from `price_spike` alerts. The filter fields must match the original subscription exactly.", - "required": [ - "op", - "event" - ], - "properties": { - "op": { - "type": "string", - "enum": [ - "unsubscribe" - ] - }, - "event": { - "type": "string", - "enum": [ - "price_spike" - ] - } - }, - "example": { - "op": "unsubscribe", - "event": "price_spike", - "position_ids": [ - "452312848583266388373324160190187140051835877600158453279131187530910662656" - ], - "condition_ids": [ - "0x0000000000000000000000000000000000000000000000000000000000000000" - ], - "event_slugs": [ - "example-event" - ], - "outcomes": [ - "Yes" - ], - "min_price_change_pct": 10.0, - "spike_direction": "up", - "window_secs": 60, - "exclude_shortterm_markets": true - } - }, - { - "$ref": "#/components/schemas/PriceSpikeFilters" - } - ] - }, - "WsAlertPriceSpikeEvent": { - "type": "object", - "required": [ - "event", - "timestamp", - "data" - ], - "description": "Pushed `price_spike` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", - "properties": { - "event": { - "type": "string", - "enum": [ - "price_spike" - ] - }, - "timestamp": { - "type": "integer", - "format": "int64", - "description": "Unix timestamp in milliseconds" - }, - "data": { - "$ref": "#/components/schemas/PriceSpikePayload" - } - }, - "example": { - "event": "price_spike", - "timestamp": 1743500000000, - "data": { - "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", - "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", - "event_slug": "test-event-0000000000", - "outcome": "Yes", - "outcome_index": 0, - "previous_price": 0.4, - "current_price": 0.5, - "spike_direction": "up", - "spike_pct": 25.0 - } - } - }, - "WsAlertMarketVolumeSpikeSubscribeMessage": { - "allOf": [ - { - "type": "object", - "description": "Subscribe to `market_volume_spike` alerts. Fired when a market's trading volume grows by a multiple of `spike_ratio` within a timeframe. Requires `spike_ratio` (> 1.0, e.g. `2.0` fires when volume doubles). Optional `window_secs` sets the observation window in seconds (max 600). Optional `timeframes` — valid values: `1m`, `5m`, `30m`, `1h`, `6h`, `1d`, `24h`, `7d`, `30d`. Optional `condition_ids` restricts to specific markets.", - "required": [ - "op", - "event" - ], - "properties": { - "op": { - "type": "string", - "enum": [ - "subscribe" - ] - }, - "event": { - "type": "string", - "enum": [ - "market_volume_spike" - ] - } - }, - "example": { - "op": "subscribe", - "event": "market_volume_spike", - "spike_ratio": 2.0, - "window_secs": 60, - "condition_ids": [ - "0x0000000000000000000000000000000000000000000000000000000000000000" - ], - "timeframes": [ - "1h" - ] - } - }, - { - "$ref": "#/components/schemas/MarketVolumeSpikeFilters" - } - ] - }, - "WsAlertMarketVolumeSpikeUnsubscribeMessage": { - "allOf": [ - { - "type": "object", - "description": "Unsubscribe from `market_volume_spike` alerts. The filter fields must match the original subscription exactly.", - "required": [ - "op", - "event" - ], - "properties": { - "op": { - "type": "string", - "enum": [ - "unsubscribe" - ] - }, - "event": { - "type": "string", - "enum": [ - "market_volume_spike" - ] - } - }, - "example": { - "op": "unsubscribe", - "event": "market_volume_spike", - "spike_ratio": 2.0, - "window_secs": 60, - "condition_ids": [ - "0x0000000000000000000000000000000000000000000000000000000000000000" - ], - "timeframes": [ - "1h" - ] - } - }, - { - "$ref": "#/components/schemas/MarketVolumeSpikeFilters" - } - ] - }, - "WsAlertMarketVolumeSpikeEvent": { - "type": "object", - "required": [ - "event", - "timestamp", - "data" - ], - "description": "Pushed `market_volume_spike` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", - "properties": { - "event": { - "type": "string", - "enum": [ - "market_volume_spike" - ] - }, - "timestamp": { - "type": "integer", - "format": "int64", - "description": "Unix timestamp in milliseconds" - }, - "data": { - "$ref": "#/components/schemas/MarketVolumeSpikePayload" - } - }, - "example": { - "event": "market_volume_spike", - "timestamp": 1743500000000, - "data": { - "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", - "timeframe": "1h", - "current_volume_usd": 32000.0, - "snapshot_volume_usd": 10000.0, - "delta_volume_usd": 22000.0, - "spike_pct": 220.0, - "txns": 480, - "fees": 160.0 - } - } - }, - "WsAlertEventVolumeSpikeSubscribeMessage": { - "allOf": [ - { - "type": "object", - "description": "Subscribe to `event_volume_spike` alerts. Fired when an event's aggregated trading volume grows by a multiple of `spike_ratio` within a timeframe. Requires `spike_ratio` (> 1.0, e.g. `2.0` fires when volume doubles). Optional `window_secs` sets the observation window in seconds (max 600). Optional `timeframes` and `event_slugs` to narrow scope.", - "required": [ - "op", - "event" - ], - "properties": { - "op": { - "type": "string", - "enum": [ - "subscribe" - ] - }, - "event": { - "type": "string", - "enum": [ - "event_volume_spike" - ] - } - }, - "example": { - "op": "subscribe", - "event": "event_volume_spike", - "spike_ratio": 2.0, - "window_secs": 60, - "event_slugs": [ - "example-event" - ], - "timeframes": [ - "1h" - ], - "exclude_shortterm_markets": true - } - }, - { - "$ref": "#/components/schemas/EventVolumeSpikeFilters" - } - ] - }, - "WsAlertEventVolumeSpikeUnsubscribeMessage": { - "allOf": [ - { - "type": "object", - "description": "Unsubscribe from `event_volume_spike` alerts. The filter fields must match the original subscription exactly.", - "required": [ - "op", - "event" - ], - "properties": { - "op": { - "type": "string", - "enum": [ - "unsubscribe" - ] - }, - "event": { - "type": "string", - "enum": [ - "event_volume_spike" - ] - } - }, - "example": { - "op": "unsubscribe", - "event": "event_volume_spike", - "spike_ratio": 2.0, - "window_secs": 60, - "event_slugs": [ - "example-event" - ], - "timeframes": [ - "1h" - ], - "exclude_shortterm_markets": true - } - }, - { - "$ref": "#/components/schemas/EventVolumeSpikeFilters" - } - ] - }, - "WsAlertEventVolumeSpikeEvent": { - "type": "object", - "required": [ - "event", - "timestamp", - "data" - ], - "description": "Pushed `event_volume_spike` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", - "properties": { - "event": { - "type": "string", - "enum": [ - "event_volume_spike" - ] - }, - "timestamp": { - "type": "integer", - "format": "int64", - "description": "Unix timestamp in milliseconds" - }, - "data": { - "$ref": "#/components/schemas/EventVolumeSpikePayload" - } - }, - "example": { - "event": "event_volume_spike", - "timestamp": 1743500000000, - "data": { - "event_slug": "test-event-0000000000", - "timeframe": "1h", - "current_volume_usd": 140000.0, - "snapshot_volume_usd": 50000.0, - "delta_volume_usd": 90000.0, - "spike_pct": 180.0, - "txns": 1100, - "fees": 700.0 - } - } - }, - "WsAlertPositionVolumeSpikeSubscribeMessage": { - "allOf": [ - { - "type": "object", - "description": "Subscribe to `position_volume_spike` alerts. Fired when a position's trading volume grows by a multiple of `spike_ratio` within a timeframe. Requires `spike_ratio` (> 1.0, e.g. `2.0` fires when volume doubles). Optional `window_secs` sets the observation window in seconds (max 600). Optional `position_ids`, `condition_ids`, `outcomes`, and `timeframes` to narrow scope.", - "required": [ - "op", - "event" - ], - "properties": { - "op": { - "type": "string", - "enum": [ - "subscribe" - ] - }, - "event": { - "type": "string", - "enum": [ - "position_volume_spike" - ] - } - }, - "example": { - "op": "subscribe", - "event": "position_volume_spike", - "spike_ratio": 2.0, - "window_secs": 60, - "position_ids": [ - "452312848583266388373324160190187140051835877600158453279131187530910662656" - ], - "condition_ids": [ - "0x0000000000000000000000000000000000000000000000000000000000000000" - ], - "outcomes": [ - "Yes" - ], - "timeframes": [ - "1h" - ] - } - }, - { - "$ref": "#/components/schemas/PositionVolumeSpikeFilters" - } - ] - }, - "WsAlertPositionVolumeSpikeUnsubscribeMessage": { - "allOf": [ - { - "type": "object", - "description": "Unsubscribe from `position_volume_spike` alerts. The filter fields must match the original subscription exactly.", - "required": [ - "op", - "event" - ], - "properties": { - "op": { - "type": "string", - "enum": [ - "unsubscribe" - ] - }, - "event": { - "type": "string", - "enum": [ - "position_volume_spike" - ] - } - }, - "example": { - "op": "unsubscribe", - "event": "position_volume_spike", - "spike_ratio": 2.0, - "window_secs": 60, - "position_ids": [ - "452312848583266388373324160190187140051835877600158453279131187530910662656" - ], - "condition_ids": [ - "0x0000000000000000000000000000000000000000000000000000000000000000" - ], - "outcomes": [ - "Yes" - ], - "timeframes": [ - "1h" - ] - } - }, - { - "$ref": "#/components/schemas/PositionVolumeSpikeFilters" - } - ] - }, - "WsAlertPositionVolumeSpikeEvent": { - "type": "object", - "required": [ - "event", - "timestamp", - "data" - ], - "description": "Pushed `position_volume_spike` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", - "properties": { - "event": { - "type": "string", - "enum": [ - "position_volume_spike" - ] - }, - "timestamp": { - "type": "integer", - "format": "int64", - "description": "Unix timestamp in milliseconds" - }, - "data": { - "$ref": "#/components/schemas/PositionVolumeSpikePayload" - } - }, - "example": { - "event": "position_volume_spike", - "timestamp": 1743500000000, - "data": { - "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", - "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", - "outcome": "Yes", - "outcome_index": 0, - "timeframe": "1h", - "current_volume_usd": 20500.0, - "snapshot_volume_usd": 5000.0, - "delta_volume_usd": 15500.0, - "spike_pct": 310.0, - "txns": 240, - "fees": 102.5 - } - } - }, - "WsAlertCloseToBondSubscribeMessage": { - "allOf": [ - { - "type": "object", - "description": "Subscribe to `close_to_bond` alerts. Fired when a trade occurs at a near-certain-outcome price. **At least one of `min_probability` or `max_probability` is required.** Use `min_probability` (e.g. `0.95`) to trigger when YES is near-certain; use `max_probability` (e.g. `0.05`) for NO near-certain. Optional filters: `position_outcome_indices` — restrict by outcome index (`0` = Yes/Up, `1` = No); `condition_ids` — restrict to specific markets; `position_ids` — restrict to specific outcome tokens; `outcomes` — restrict by outcome name (e.g. `\"Yes\"`, `\"No\"`); `event_slugs` — restrict to specific events.", - "required": [ - "op", - "event" - ], - "properties": { - "op": { - "type": "string", - "enum": [ - "subscribe" - ] - }, - "event": { - "type": "string", - "enum": [ - "close_to_bond" - ] - } - }, - "example": { - "op": "subscribe", - "event": "close_to_bond", - "min_probability": 0.95, - "max_probability": 0.05, - "condition_ids": [ - "0x0000000000000000000000000000000000000000000000000000000000000000" - ], - "position_ids": [ - "452312848583266388373324160190187140051835877600158453279131187530910662656" - ], - "outcomes": [ - "Yes" - ], - "position_outcome_indices": [ - 0 - ], - "event_slugs": [ - "example-event" - ], - "exclude_shortterm_markets": true - } - }, - { - "$ref": "#/components/schemas/CloseToBondFilters" - } - ], - "anyOf": [ - { - "required": [ - "min_probability" - ] - }, - { - "required": [ - "max_probability" - ] - } - ] - }, - "WsAlertCloseToBondUnsubscribeMessage": { - "allOf": [ - { - "type": "object", - "description": "Unsubscribe from `close_to_bond` alerts. The filter fields must match the original subscription exactly.", - "required": [ - "op", - "event" - ], - "properties": { - "op": { - "type": "string", - "enum": [ - "unsubscribe" - ] - }, - "event": { - "type": "string", - "enum": [ - "close_to_bond" - ] - } - }, - "example": { - "op": "unsubscribe", - "event": "close_to_bond", - "min_probability": 0.95, - "max_probability": 0.05, - "condition_ids": [ - "0x0000000000000000000000000000000000000000000000000000000000000000" - ], - "position_ids": [ - "452312848583266388373324160190187140051835877600158453279131187530910662656" - ], - "outcomes": [ - "Yes" - ], - "position_outcome_indices": [ - 0 - ], - "event_slugs": [ - "example-event" - ], - "exclude_shortterm_markets": true - } - }, - { - "$ref": "#/components/schemas/CloseToBondFilters" - } - ], - "anyOf": [ - { - "required": [ - "min_probability" - ] - }, - { - "required": [ - "max_probability" - ] - } - ] - }, - "WsAlertCloseToBondEvent": { - "type": "object", - "required": [ - "event", - "timestamp", - "data" - ], - "description": "Pushed `close_to_bond` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", - "properties": { - "event": { - "type": "string", - "enum": [ - "close_to_bond" - ] - }, - "timestamp": { - "type": "integer", - "format": "int64", - "description": "Unix timestamp in milliseconds" - }, - "data": { - "$ref": "#/components/schemas/CloseToBondPayload" - } - }, - "example": { - "event": "close_to_bond", - "timestamp": 1743500000000, - "data": { - "trader": "0x0000000000000000000000000000000000000000", - "taker": "0x0000000000000000000000000000000000000000", - "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", - "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", - "outcome": "Yes", - "outcome_index": 0, - "question": "Will this test webhook fire correctly?", - "market_slug": "test-market-0000000000", - "event_slug": "test-event-0000000000", - "trade_id": "00000000-0000-0000-0000-000000000000", - "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "block": 0, - "confirmed_at": 1700000000, - "amount_usd": 500.0, - "shares_amount": 515.46, - "fee": 2.5, - "side": "Buy", - "price": 0.97, - "probability": 0.97, - "bond_side": "high", - "threshold": 0.95 - } - } - }, - "WsAlertMarketCreatedSubscribeMessage": { - "allOf": [ - { - "type": "object", - "description": "Subscribe to `market_created` alerts. Fired when a new prediction market is created on Polymarket. Filterable by `tags` and `event_slugs`.", - "required": [ - "op", - "event" - ], - "properties": { - "op": { - "type": "string", - "enum": [ - "subscribe" - ] - }, - "event": { - "type": "string", - "enum": [ - "market_created" - ] - } - }, - "example": { - "op": "subscribe", - "event": "market_created", - "event_slugs": [ - "example-event" - ], - "tags": [ - "Politics" - ], - "exclude_shortterm_markets": true - } - }, - { - "$ref": "#/components/schemas/MarketCreatedFilters" - } - ] - }, - "WsAlertMarketCreatedUnsubscribeMessage": { - "allOf": [ - { - "type": "object", - "description": "Unsubscribe from `market_created` alerts. The filter fields must match the original subscription exactly.", - "required": [ - "op", - "event" - ], - "properties": { - "op": { - "type": "string", - "enum": [ - "unsubscribe" - ] - }, - "event": { - "type": "string", - "enum": [ - "market_created" - ] - } - }, - "example": { - "op": "unsubscribe", - "event": "market_created", - "event_slugs": [ - "example-event" - ], - "tags": [ - "Politics" - ], - "exclude_shortterm_markets": true - } - }, - { - "$ref": "#/components/schemas/MarketCreatedFilters" - } - ] - }, - "WsAlertMarketCreatedEvent": { - "type": "object", - "required": [ - "event", - "timestamp", - "data" - ], - "description": "Pushed `market_created` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", - "properties": { - "event": { - "type": "string", - "enum": [ - "market_created" - ] - }, - "timestamp": { - "type": "integer", - "format": "int64", - "description": "Unix timestamp in milliseconds" - }, - "data": { - "$ref": "#/components/schemas/MarketCreatedPayload" - } - }, - "example": { - "event": "market_created", - "timestamp": 1743500000000, - "data": { - "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", - "market_slug": "test-market-0000000000", - "event_slug": "test-event-0000000000", - "event_id": null, - "event_title": "Test Event 0000", - "series_slug": null, - "outcomes": [ - { - "index": 0, - "name": "Yes", - "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656" - }, - { - "index": 1, - "name": "No", - "position_id": "0" - } - ], - "question": "Will this test webhook fire correctly?", - "title": "Test Market 0000", - "description": "A test market for webhook payload verification.", - "category": "Crypto", - "tags": [ - "test", - "crypto" - ], - "image_url": null, - "neg_risk": false - } - } - }, - "WsAlertAssetPriceTickSubscribeMessage": { - "allOf": [ - { - "type": "object", - "description": "Subscribe to `asset_price_tick` alerts. Fired when the price of a tracked crypto asset updates (BTC, ETH, SOL, XRP, DOGE, BNB, HYPE). Use `asset_symbols` to restrict to specific assets (empty = all).", - "required": [ - "op", - "event" - ], - "properties": { - "op": { - "type": "string", - "enum": [ - "subscribe" - ] - }, - "event": { - "type": "string", - "enum": [ - "asset_price_tick" - ] - } - }, - "example": { - "op": "subscribe", - "event": "asset_price_tick", - "asset_symbols": [ - "BTC" - ] - } - }, - { - "$ref": "#/components/schemas/AssetPriceTickFilters" - } - ] - }, - "WsAlertAssetPriceTickUnsubscribeMessage": { - "allOf": [ - { - "type": "object", - "description": "Unsubscribe from `asset_price_tick` alerts. The filter fields must match the original subscription exactly.", - "required": [ - "op", - "event" - ], - "properties": { - "op": { - "type": "string", - "enum": [ - "unsubscribe" - ] - }, - "event": { - "type": "string", - "enum": [ - "asset_price_tick" - ] - } - }, - "example": { - "op": "unsubscribe", - "event": "asset_price_tick", - "asset_symbols": [ - "BTC" - ] - } - }, - { - "$ref": "#/components/schemas/AssetPriceTickFilters" - } - ] - }, - "WsAlertAssetPriceTickEvent": { - "type": "object", - "required": [ - "event", - "timestamp", - "data" - ], - "description": "Pushed `asset_price_tick` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", - "properties": { - "event": { - "type": "string", - "enum": [ - "asset_price_tick" - ] - }, - "timestamp": { - "type": "integer", - "format": "int64", - "description": "Unix timestamp in milliseconds" - }, - "data": { - "$ref": "#/components/schemas/AssetPriceTickPayload" - } - }, - "example": { - "event": "asset_price_tick", - "timestamp": 1743500000000, - "data": { - "symbol": "BTC", - "price": 65000.0, - "timestamp_ms": 1700000000000 - } - } - }, - "WsAlertAssetPriceWindowUpdateSubscribeMessage": { - "allOf": [ - { - "type": "object", - "description": "Subscribe to `asset_price_window_update` alerts. Fired at the start and end of each price candle for tracked crypto assets (BTC, ETH, SOL, XRP, DOGE, BNB, HYPE). Payload includes `update_type` (`\"open\"` or `\"close\"`) indicating whether the candle is opening or closing. Use `asset_symbols` to restrict to specific assets. Use `timeframes` to restrict to specific candle sizes — valid values: `\"5m\"`, `\"15m\"`, `\"1h\"`, `\"4h\"`, `\"1d\"`, `\"24h\"`.", - "required": [ - "op", - "event" - ], - "properties": { - "op": { - "type": "string", - "enum": [ - "subscribe" - ] - }, - "event": { - "type": "string", - "enum": [ - "asset_price_window_update" - ] - } - }, - "example": { - "op": "subscribe", - "event": "asset_price_window_update", - "asset_symbols": [ - "BTC" - ], - "timeframes": [ - "1h" - ] - } - }, - { - "$ref": "#/components/schemas/AssetPriceWindowUpdateFilters" - } - ] - }, - "WsAlertAssetPriceWindowUpdateUnsubscribeMessage": { - "allOf": [ - { - "type": "object", - "description": "Unsubscribe from `asset_price_window_update` alerts. The filter fields must match the original subscription exactly.", - "required": [ - "op", - "event" - ], - "properties": { - "op": { - "type": "string", - "enum": [ - "unsubscribe" - ] - }, - "event": { - "type": "string", - "enum": [ - "asset_price_window_update" - ] - } - }, - "example": { - "op": "unsubscribe", - "event": "asset_price_window_update", - "asset_symbols": [ - "BTC" - ], - "timeframes": [ - "1h" - ] - } - }, - { - "$ref": "#/components/schemas/AssetPriceWindowUpdateFilters" - } - ] - }, - "WsAlertAssetPriceWindowUpdateEvent": { - "type": "object", - "required": [ - "event", - "timestamp", - "data" - ], - "description": "Pushed `asset_price_window_update` alert. The `data` payload matches the corresponding HTTP webhook payload schema.", - "properties": { - "event": { - "type": "string", - "enum": [ - "asset_price_window_update" - ] - }, - "timestamp": { - "type": "integer", - "format": "int64", - "description": "Unix timestamp in milliseconds" - }, - "data": { - "$ref": "#/components/schemas/AssetPriceWindowUpdatePayload" - } - }, - "example": { - "event": "asset_price_window_update", - "timestamp": 1743500000000, - "data": { - "symbol": "BTC", - "variant": "1h", - "start_time": 1700000000000, - "end_time": 1700003600000, - "open_price": 64800.0, - "close_price": 65200.0, - "update_type": "close" - } - } - }, - "WsAlertSubscribeMessage": { - "description": "Typed subscribe request for the alerts WebSocket. The request shape depends on `event` and reuses the matching webhook filter schema.", - "oneOf": [ - { - "$ref": "#/components/schemas/WsAlertTraderFirstTradeSubscribeMessage" - }, - { - "$ref": "#/components/schemas/WsAlertTraderNewMarketSubscribeMessage" - }, - { - "$ref": "#/components/schemas/WsAlertTraderWhaleTradeSubscribeMessage" - }, - { - "$ref": "#/components/schemas/WsAlertTraderNewTradeSubscribeMessage" - }, - { - "$ref": "#/components/schemas/WsAlertTraderGlobalPnlSubscribeMessage" - }, - { - "$ref": "#/components/schemas/WsAlertTraderMarketPnlSubscribeMessage" - }, - { - "$ref": "#/components/schemas/WsAlertTraderEventPnlSubscribeMessage" - }, - { - "$ref": "#/components/schemas/WsAlertConditionMetricsSubscribeMessage" - }, - { - "$ref": "#/components/schemas/WsAlertEventMetricsSubscribeMessage" - }, - { - "$ref": "#/components/schemas/WsAlertPositionMetricsSubscribeMessage" - }, - { - "$ref": "#/components/schemas/WsAlertMarketVolumeMilestoneSubscribeMessage" - }, - { - "$ref": "#/components/schemas/WsAlertEventVolumeMilestoneSubscribeMessage" - }, - { - "$ref": "#/components/schemas/WsAlertPositionVolumeMilestoneSubscribeMessage" - }, - { - "$ref": "#/components/schemas/WsAlertProbabilitySpikeSubscribeMessage" - }, - { - "$ref": "#/components/schemas/WsAlertPriceSpikeSubscribeMessage" - }, - { - "$ref": "#/components/schemas/WsAlertMarketVolumeSpikeSubscribeMessage" - }, - { - "$ref": "#/components/schemas/WsAlertEventVolumeSpikeSubscribeMessage" - }, - { - "$ref": "#/components/schemas/WsAlertPositionVolumeSpikeSubscribeMessage" - }, - { - "$ref": "#/components/schemas/WsAlertCloseToBondSubscribeMessage" - }, - { - "$ref": "#/components/schemas/WsAlertMarketCreatedSubscribeMessage" - }, - { - "$ref": "#/components/schemas/WsAlertAssetPriceTickSubscribeMessage" - }, - { - "$ref": "#/components/schemas/WsAlertAssetPriceWindowUpdateSubscribeMessage" - } - ], - "discriminator": { - "propertyName": "event" - } - }, - "WsAlertUnsubscribeMessage": { - "description": "Typed unsubscribe request for the alerts WebSocket. The request shape depends on `event` and must match the original subscription filters.", - "oneOf": [ - { - "$ref": "#/components/schemas/WsAlertTraderFirstTradeUnsubscribeMessage" - }, - { - "$ref": "#/components/schemas/WsAlertTraderNewMarketUnsubscribeMessage" - }, - { - "$ref": "#/components/schemas/WsAlertTraderWhaleTradeUnsubscribeMessage" - }, - { - "$ref": "#/components/schemas/WsAlertTraderNewTradeUnsubscribeMessage" - }, - { - "$ref": "#/components/schemas/WsAlertTraderGlobalPnlUnsubscribeMessage" - }, - { - "$ref": "#/components/schemas/WsAlertTraderMarketPnlUnsubscribeMessage" - }, - { - "$ref": "#/components/schemas/WsAlertTraderEventPnlUnsubscribeMessage" - }, - { - "$ref": "#/components/schemas/WsAlertConditionMetricsUnsubscribeMessage" - }, - { - "$ref": "#/components/schemas/WsAlertEventMetricsUnsubscribeMessage" - }, - { - "$ref": "#/components/schemas/WsAlertPositionMetricsUnsubscribeMessage" - }, - { - "$ref": "#/components/schemas/WsAlertMarketVolumeMilestoneUnsubscribeMessage" - }, - { - "$ref": "#/components/schemas/WsAlertEventVolumeMilestoneUnsubscribeMessage" - }, - { - "$ref": "#/components/schemas/WsAlertPositionVolumeMilestoneUnsubscribeMessage" - }, - { - "$ref": "#/components/schemas/WsAlertProbabilitySpikeUnsubscribeMessage" - }, - { - "$ref": "#/components/schemas/WsAlertPriceSpikeUnsubscribeMessage" - }, - { - "$ref": "#/components/schemas/WsAlertMarketVolumeSpikeUnsubscribeMessage" - }, - { - "$ref": "#/components/schemas/WsAlertEventVolumeSpikeUnsubscribeMessage" - }, - { - "$ref": "#/components/schemas/WsAlertPositionVolumeSpikeUnsubscribeMessage" - }, - { - "$ref": "#/components/schemas/WsAlertCloseToBondUnsubscribeMessage" - }, - { - "$ref": "#/components/schemas/WsAlertMarketCreatedUnsubscribeMessage" - }, - { - "$ref": "#/components/schemas/WsAlertAssetPriceTickUnsubscribeMessage" - }, - { - "$ref": "#/components/schemas/WsAlertAssetPriceWindowUpdateUnsubscribeMessage" - } - ], - "discriminator": { - "propertyName": "event" - } - }, - "WsAlertEventPayload": { - "description": "Typed pushed-event envelope for the alerts WebSocket. The `data` payload depends on `event` and matches the corresponding HTTP webhook payload schema.", - "oneOf": [ - { - "$ref": "#/components/schemas/WsAlertTraderFirstTradeEvent" - }, - { - "$ref": "#/components/schemas/WsAlertTraderNewMarketEvent" - }, - { - "$ref": "#/components/schemas/WsAlertTraderWhaleTradeEvent" - }, - { - "$ref": "#/components/schemas/WsAlertTraderNewTradeEvent" - }, - { - "$ref": "#/components/schemas/WsAlertTraderGlobalPnlEvent" - }, - { - "$ref": "#/components/schemas/WsAlertTraderMarketPnlEvent" - }, - { - "$ref": "#/components/schemas/WsAlertTraderEventPnlEvent" - }, - { - "$ref": "#/components/schemas/WsAlertConditionMetricsEvent" - }, - { - "$ref": "#/components/schemas/WsAlertEventMetricsEvent" - }, - { - "$ref": "#/components/schemas/WsAlertPositionMetricsEvent" - }, - { - "$ref": "#/components/schemas/WsAlertMarketVolumeMilestoneEvent" - }, - { - "$ref": "#/components/schemas/WsAlertEventVolumeMilestoneEvent" - }, - { - "$ref": "#/components/schemas/WsAlertPositionVolumeMilestoneEvent" - }, - { - "$ref": "#/components/schemas/WsAlertProbabilitySpikeEvent" - }, - { - "$ref": "#/components/schemas/WsAlertPriceSpikeEvent" - }, - { - "$ref": "#/components/schemas/WsAlertMarketVolumeSpikeEvent" - }, - { - "$ref": "#/components/schemas/WsAlertEventVolumeSpikeEvent" - }, - { - "$ref": "#/components/schemas/WsAlertPositionVolumeSpikeEvent" - }, - { - "$ref": "#/components/schemas/WsAlertCloseToBondEvent" - }, - { - "$ref": "#/components/schemas/WsAlertMarketCreatedEvent" - }, - { - "$ref": "#/components/schemas/WsAlertAssetPriceTickEvent" - }, - { - "$ref": "#/components/schemas/WsAlertAssetPriceWindowUpdateEvent" - } - ], - "discriminator": { - "propertyName": "event" - } } }, "securitySchemes": { - "jwt": { + "apiKeyHeader": { + "type": "httpApiKey", + "in": "header", + "name": "X-Api-Key", + "description": "Pass the API key via the `X-Api-Key` header on the WebSocket upgrade request." + }, + "apiKeyQuery": { + "type": "httpApiKey", + "in": "query", + "name": "api_key", + "description": "Pass the API key via `?api_key=` on the WebSocket upgrade URL (browser/frontend friendly)." + }, + "publicKeyJwt": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT", - "description": "Send `{\"type\":\"authenticate\",\"jwt\":\"\"}` after connecting" + "description": "Public-key JWT combo: the builder embeds a `pk_jwt_*` key in their frontend, and end users supply a JWT signed by the builder. Send via `Authorization: Bearer ` header or `?token=` query parameter. Credits bill to the builder's org; rate limits are applied per session." } } } diff --git a/scripts/check-routes.ts b/scripts/check-routes.ts index 072f95f..36dffa9 100644 --- a/scripts/check-routes.ts +++ b/scripts/check-routes.ts @@ -114,9 +114,7 @@ async function getSpecSchemas(jsonSpecPath: string): Promise { async function getExportedSchemas(typesContent: string): Promise> { const exported = new Set(); - for (const m of typesContent.matchAll(/Schemas\["(\w+)"\]/g)) exported.add(m[1]); - for (const m of typesContent.matchAll(/WebhookSchemas\["(\w+)"\]/g)) exported.add(m[1]); - for (const m of typesContent.matchAll(/WsSchemas\["(\w+)"\]/g)) exported.add(m[1]); + for (const m of typesContent.matchAll(/(?:\w+)?Schemas\["(\w+)"\]/g)) exported.add(m[1]); for (const m of typesContent.matchAll(/components\["schemas"\]\["(\w+)"\]/g)) exported.add(m[1]); for (const m of typesContent.matchAll(/export type (\w+)\s*=/g)) exported.add(m[1]); for (const m of typesContent.matchAll(/export interface (\w+)/g)) exported.add(m[1]); @@ -128,24 +126,34 @@ async function getWsSpecRooms(jsonSpecPath: string): Promise { return Object.keys(spec.channels ?? {}); } -async function getSdkWsRooms(): Promise> { - const content = await readFile(WS_TYPES_FILE, "utf-8"); - const rooms = new Set(); - const subscriptionMapMatch = content.match(/interface WsSubscriptionMap\s*\{([^}]+)\}/); - if (subscriptionMapMatch) { - const regex = /(\w+)\s*:/g; - let match: RegExpExecArray | null; - while ((match = regex.exec(subscriptionMapMatch[1])) !== null) { - rooms.add(match[1]); - } +function extractInterfaceKeys(content: string, interfaceName: string): Set { + const keys = new Set(); + const re = new RegExp(`interface\\s+${interfaceName}\\s*\\{([\\s\\S]*?)\\n\\}`); + const match = content.match(re); + if (!match) return keys; + const body = match[1]; + const keyRegex = /^\s*(\w+)\s*:/gm; + let km: RegExpExecArray | null; + while ((km = keyRegex.exec(body)) !== null) { + keys.add(km[1]); } + return keys; +} + +async function getSdkStreamingRooms(): Promise> { + const content = await readFile(WS_TYPES_FILE, "utf-8"); + return extractInterfaceKeys(content, "WsSubscriptionMap"); +} + +async function getSdkAlertEvents(): Promise> { try { const alertsContent = await readFile(WS_ALERTS_FILE, "utf-8"); - if (/class\s+StructAlertsWebSocket\b/.test(alertsContent)) { - rooms.add("ws_alerts"); - } - } catch {} - return rooms; + if (!/class\s+StructAlertsWebSocket\b/.test(alertsContent)) return new Set(); + } catch { + return new Set(); + } + const generated = await readFile(join(import.meta.dirname, "../src/generated/ws-alerts.ts"), "utf-8"); + return extractInterfaceKeys(generated, "WsAlertSubscribeMap"); } let hasErrors = false; @@ -153,7 +161,8 @@ let hasErrors = false; const typesContent = await readFile(TYPES_FILE, "utf-8"); const wsTypesContent = await readFile(join(import.meta.dirname, "../src/types/ws.ts"), "utf-8"); const wsGeneratedContent = await readFile(join(import.meta.dirname, "../src/generated/ws.ts"), "utf-8"); -const combinedTypesContent = typesContent + "\n" + wsTypesContent + "\n" + wsGeneratedContent; +const wsAlertsGeneratedContent = await readFile(join(import.meta.dirname, "../src/generated/ws-alerts.ts"), "utf-8"); +const combinedTypesContent = [typesContent, wsTypesContent, wsGeneratedContent, wsAlertsGeneratedContent].join("\n"); const exportedSchemas = await getExportedSchemas(combinedTypesContent); for (const config of specs) { @@ -209,35 +218,51 @@ for (const config of specs) { } const wsJsonPath = join(import.meta.dirname, "../openapi/ws.json"); -const wsSpecRooms = await getWsSpecRooms(wsJsonPath); -const sdkWsRooms = await getSdkWsRooms(); +const wsAlertsJsonPath = join(import.meta.dirname, "../openapi/ws-alerts.json"); -const phantomWsRooms = [...sdkWsRooms].filter((r) => !wsSpecRooms.includes(r)); -const missingWsRooms = wsSpecRooms.filter((r) => !sdkWsRooms.has(r)); +interface WsCheckConfig { + label: string; + specRooms: string[]; + sdkRooms: Set; +} -if (phantomWsRooms.length > 0) { - hasErrors = true; - console.error(`\x1b[31m✗ [ws] Phantom rooms (SDK rooms not in WS OpenAPI spec):\x1b[0m\n`); - for (const r of phantomWsRooms) { - console.error(` ${r}`); +const streamingSpecRooms = await getWsSpecRooms(wsJsonPath); +const alertsSpecChannels = await getWsSpecRooms(wsAlertsJsonPath); +const alertsSpecEvents = alertsSpecChannels + .filter((c) => c.startsWith("ws_alerts.")) + .map((c) => c.slice("ws_alerts.".length)); + +const wsChecks: WsCheckConfig[] = [ + { label: "ws", specRooms: streamingSpecRooms, sdkRooms: await getSdkStreamingRooms() }, + { label: "ws-alerts", specRooms: alertsSpecEvents, sdkRooms: await getSdkAlertEvents() }, +]; + +for (const check of wsChecks) { + const phantom = [...check.sdkRooms].filter((r) => !check.specRooms.includes(r)); + const missing = check.specRooms.filter((r) => !check.sdkRooms.has(r)); + + if (phantom.length > 0) { + hasErrors = true; + console.error(`\x1b[31m✗ [${check.label}] Phantom rooms (SDK rooms not in WS OpenAPI spec):\x1b[0m\n`); + for (const r of phantom) console.error(` ${r}`); + console.error(); } - console.error(); -} -if (missingWsRooms.length > 0) { - hasErrors = true; - console.error(`\x1b[31m✗ [ws] Unimplemented rooms (WS OpenAPI spec rooms missing from SDK):\x1b[0m\n`); - for (const r of missingWsRooms) { - console.error(` ${r}`); + if (missing.length > 0) { + hasErrors = true; + console.error(`\x1b[31m✗ [${check.label}] Unimplemented rooms (WS OpenAPI spec rooms missing from SDK):\x1b[0m\n`); + for (const r of missing) console.error(` ${r}`); + console.error(); } - console.error(); -} -if (phantomWsRooms.length === 0 && missingWsRooms.length === 0) { - console.log(`\x1b[32m✓ [ws] All SDK rooms match the WS OpenAPI spec.\x1b[0m`); + if (phantom.length === 0 && missing.length === 0) { + console.log(`\x1b[32m✓ [${check.label}] All SDK rooms match the WS OpenAPI spec.\x1b[0m`); + } } -const wsSpecSchemas = await getSpecSchemas(wsJsonPath); +const wsJsonPaths = [wsJsonPath, wsAlertsJsonPath]; +const wsSpecSchemasList = (await Promise.all(wsJsonPaths.map(getSpecSchemas))).flat(); +const wsSpecSchemas = [...new Set(wsSpecSchemasList)]; const missingWsSchemas = wsSpecSchemas.filter((s) => !exportedSchemas.has(s)); if (missingWsSchemas.length > 0) { diff --git a/scripts/fetch-specs.ts b/scripts/fetch-specs.ts index 2d35bb5..20c38b3 100644 --- a/scripts/fetch-specs.ts +++ b/scripts/fetch-specs.ts @@ -12,6 +12,7 @@ const SPECS = [ { name: "polymarket", path: "/api-docs/openapi.json", output: "openapi/polymarket.json" }, { name: "webhooks", path: "/webhookopenapi.json", output: "openapi/webhooks.json" }, { name: "ws", path: "/asyncapi.json", output: "openapi/ws.json" }, + { name: "ws-alerts", path: "/asyncapi-alerts.json", output: "openapi/ws-alerts.json" }, ] as const; const raw = (Bun.env.STRUCT_ENV ?? "production").toLowerCase(); diff --git a/scripts/generate-ws-types.ts b/scripts/generate-ws-types.ts index 064787c..af8712e 100644 --- a/scripts/generate-ws-types.ts +++ b/scripts/generate-ws-types.ts @@ -2,100 +2,151 @@ import openapiTS, { astToString } from "openapi-typescript"; import { readFile, writeFile } from "node:fs/promises"; import { join } from "node:path"; -const asyncapiPath = join(import.meta.dirname, "../openapi/ws.json"); -const outputPath = join(import.meta.dirname, "../src/generated/ws.ts"); - -const asyncapi = JSON.parse(await readFile(asyncapiPath, "utf-8")); -const schemas = asyncapi.components.schemas; - -for (const schema of Object.values(schemas) as Array>) { - const required = new Set((schema.required as string[]) ?? []); - const properties = schema.properties as Record> | undefined; - if (!properties) continue; - for (const [propName, prop] of Object.entries(properties)) { - if ("default" in prop && !required.has(propName)) { - delete prop.default; - } - } +const root = join(import.meta.dirname, ".."); + +interface SpecConfig { + name: string; + inputPath: string; + outputPath: string; + withAlertDiscriminators?: boolean; } +const SPECS: SpecConfig[] = [ + { + name: "ws", + inputPath: join(root, "openapi/ws.json"), + outputPath: join(root, "src/generated/ws.ts"), + }, + { + name: "ws-alerts", + inputPath: join(root, "openapi/ws-alerts.json"), + outputPath: join(root, "src/generated/ws-alerts.ts"), + withAlertDiscriminators: true, + }, +]; + const ALERT_DISCRIMINATED_SCHEMAS = [ "WsAlertSubscribeMessage", "WsAlertUnsubscribeMessage", "WsAlertEventPayload", ] as const; -for (const parentName of ALERT_DISCRIMINATED_SCHEMAS) { - const parent = schemas[parentName]; - if (!parent?.oneOf || !parent?.discriminator) continue; - - const mapping: Record = {}; - for (const variant of parent.oneOf) { - const ref = variant.$ref as string | undefined; - if (!ref) continue; - const schemaName = ref.split("/").pop()!; - const variantSchema = schemas[schemaName]; - - let eventValue: string | undefined; - const allOf = variantSchema?.allOf as Array> | undefined; - if (allOf) { - for (const part of allOf) { - const props = part.properties as Record | undefined; - eventValue ??= props?.event?.enum?.[0]; +function stripOptionalDefaults(schemas: Record>): void { + for (const schema of Object.values(schemas)) { + const required = new Set((schema.required as string[]) ?? []); + const properties = schema.properties as Record> | undefined; + if (!properties) continue; + for (const [propName, prop] of Object.entries(properties)) { + if ("default" in prop && !required.has(propName)) { + delete prop.default; } } - eventValue ??= variantSchema?.properties?.event?.enum?.[0]; + } +} - if (eventValue) { - mapping[eventValue] = ref; +function buildAlertDiscriminatorMappings(schemas: Record>): void { + for (const parentName of ALERT_DISCRIMINATED_SCHEMAS) { + const parent = schemas[parentName] as + | { oneOf?: Array<{ $ref?: string }>; discriminator?: unknown } + | undefined; + if (!parent?.oneOf || parent.discriminator === undefined) continue; + + const propertyName = + typeof parent.discriminator === "string" + ? parent.discriminator + : (parent.discriminator as { propertyName?: string }).propertyName ?? "event"; + + const mapping: Record = {}; + for (const variant of parent.oneOf) { + const ref = variant.$ref; + if (!ref) continue; + const schemaName = ref.split("/").pop()!; + const variantSchema = schemas[schemaName]; + + let eventValue: string | undefined; + const allOf = variantSchema?.allOf as Array> | undefined; + if (allOf) { + for (const part of allOf) { + const props = part.properties as Record | undefined; + eventValue ??= props?.[propertyName]?.enum?.[0]; + } + } + const props = variantSchema?.properties as Record | undefined; + eventValue ??= props?.[propertyName]?.enum?.[0]; + + if (eventValue) { + mapping[eventValue] = ref; + } } - } - parent.discriminator.mapping = mapping; + (parent as Record).discriminator = { propertyName, mapping }; + } } -const ast = await openapiTS({ - openapi: "3.1.0", - info: asyncapi.info, - paths: {}, - components: { schemas }, -}); - -let output = astToString(ast); +function buildAlertMapOutput(schemas: Record>): string { + const subscribeEntries: string[] = []; + const eventDataEntries: string[] = []; -const eventNames: string[] = []; -const subscribeEntries: string[] = []; -const eventDataEntries: string[] = []; + const subscribeMapping = (schemas.WsAlertSubscribeMessage as { discriminator?: { mapping?: Record } } | undefined) + ?.discriminator?.mapping; + const eventMapping = (schemas.WsAlertEventPayload as { discriminator?: { mapping?: Record } } | undefined) + ?.discriminator?.mapping; -const subscribeMapping = schemas.WsAlertSubscribeMessage?.discriminator?.mapping as Record | undefined; -const eventMapping = schemas.WsAlertEventPayload?.discriminator?.mapping as Record | undefined; + if (subscribeMapping) { + for (const [eventName, ref] of Object.entries(subscribeMapping)) { + const schemaName = ref.split("/").pop()!; + subscribeEntries.push(`\t${eventName}: components["schemas"]["${schemaName}"];`); + } + } -if (subscribeMapping) { - for (const [eventName, ref] of Object.entries(subscribeMapping)) { - const schemaName = ref.split("/").pop()!; - subscribeEntries.push(`\t${eventName}: components["schemas"]["${schemaName}"];`); + if (eventMapping) { + for (const [eventName, ref] of Object.entries(eventMapping)) { + const schemaName = ref.split("/").pop()!; + const eventSchema = schemas[schemaName] as { properties?: { data?: { $ref?: string } } } | undefined; + const dataRef = eventSchema?.properties?.data?.$ref; + const dataSchemaName = dataRef?.split("/").pop(); + if (dataSchemaName) { + eventDataEntries.push(`\t${eventName}: components["schemas"]["${dataSchemaName}"];`); + } + } } + + if (subscribeEntries.length === 0) return ""; + + return ( + `\nexport interface WsAlertSubscribeMap {\n${subscribeEntries.join("\n")}\n}\n` + + `\nexport interface WsAlertEventDataMap {\n${eventDataEntries.join("\n")}\n}\n` + + `\nexport type WsAlertEventName = keyof WsAlertSubscribeMap;\n` + ); } -if (eventMapping) { - for (const [eventName, ref] of Object.entries(eventMapping)) { - const schemaName = ref.split("/").pop()!; - eventNames.push(eventName); +async function generateSpec(spec: SpecConfig): Promise { + const asyncapi = JSON.parse(await readFile(spec.inputPath, "utf-8")); + const schemas = asyncapi.components.schemas as Record>; - const eventSchema = schemas[schemaName]; - const dataRef = eventSchema?.properties?.data?.$ref as string | undefined; - const dataSchemaName = dataRef?.split("/").pop(); - if (dataSchemaName) { - eventDataEntries.push(`\t${eventName}: components["schemas"]["${dataSchemaName}"];`); - } + stripOptionalDefaults(schemas); + + if (spec.withAlertDiscriminators) { + buildAlertDiscriminatorMappings(schemas); } -} -if (subscribeEntries.length > 0) { - output += `\nexport interface WsAlertSubscribeMap {\n${subscribeEntries.join("\n")}\n}\n`; - output += `\nexport interface WsAlertEventDataMap {\n${eventDataEntries.join("\n")}\n}\n`; - output += `\nexport type WsAlertEventName = keyof WsAlertSubscribeMap;\n`; + const ast = await openapiTS({ + openapi: "3.1.0", + info: asyncapi.info, + paths: {}, + components: { schemas }, + }); + + let output = astToString(ast); + + if (spec.withAlertDiscriminators) { + output += buildAlertMapOutput(schemas); + } + + await writeFile(spec.outputPath, output); + console.log(`✓ Generated ${spec.name} types`); } -await writeFile(outputPath, output); -console.log("✓ Generated WS types from AsyncAPI spec"); +for (const spec of SPECS) { + await generateSpec(spec); +} diff --git a/src/generated/polymarket.ts b/src/generated/polymarket.ts index d0eac83..95e2f61 100644 --- a/src/generated/polymarket.ts +++ b/src/generated/polymarket.ts @@ -1926,6 +1926,8 @@ export interface components { * @description Outcome index (0 = Yes, 1 = No for binary) */ outcome_index: number; + /** @description Outcome name (e.g. "Yes", "No") — enriched from market metadata */ + outcome?: string | null; /** @description Amount of shares created/burned/redeemed for this position */ amount: string; }; diff --git a/src/generated/ws-alerts.ts b/src/generated/ws-alerts.ts new file mode 100644 index 0000000..718f963 --- /dev/null +++ b/src/generated/ws-alerts.ts @@ -0,0 +1,2602 @@ +export type paths = Record; +export type webhooks = Record; +export interface components { + schemas: { + /** @description Outer envelope for every webhook HTTP POST delivery. The `data` field contains the event-specific payload. Delivery headers sent with every POST: `X-Webhook-ID` (subscription UUID), `X-Delivery-ID` (this attempt's UUID), `X-Event-Type` (event name string, e.g. `trader_first_trade`), `X-Attempt` (attempt number, 1-indexed). When the webhook has a secret configured, `X-Webhook-Signature: sha256=` is also included — compute HMAC-SHA256 over the raw request body using your secret to verify. */ + WebhookDeliveryEnvelope: { + /** + * Format: uuid + * @description UUID of this specific delivery attempt (matches X-Delivery-ID header) + */ + id: string; + /** @description Event name (e.g. `trader_first_trade`). On test deliveries the suffix `_test` is appended. */ + event: string; + /** @description Event-specific payload — schema varies by event type; see the individual callback definitions */ + data: Record; + /** + * Format: int64 + * @description Unix timestamp in milliseconds when this delivery was created + */ + timestamp: number; + /** + * Format: uuid + * @description UUID of the webhook subscription that fired (matches X-Webhook-ID header) + */ + webhook_id: string; + /** @description Delivery attempt number. 1 = first attempt; increments on each retry. */ + attempt: number; + }; + /** @description Payload delivered when a tracked trader executes their first-ever trade on Polymarket */ + FirstTradePayload: { + /** @description Limit-order maker wallet address (lowercase) */ + trader: string; + /** @description Order filler wallet address (lowercase) */ + taker: string; + /** @description ERC-1155 outcome token ID */ + position_id: string; + /** @description Parent market condition ID (0x-prefixed hex) */ + condition_id?: string | null; + /** @description Outcome name (e.g. "Yes", "No") */ + outcome?: string | null; + /** @description Outcome index: 0 = Yes/Up, 1 = No */ + outcome_index?: number | null; + /** @description Market question text */ + question?: string | null; + /** @description Market slug */ + market_slug?: string | null; + /** @description Parent event slug */ + event_slug?: string | null; + /** @description Unique trade identifier */ + trade_id: string; + /** @description Transaction hash */ + hash: string; + /** + * Format: int64 + * @description Block number + */ + block: number; + /** + * Format: int64 + * @description Block confirmation timestamp (Unix seconds) + */ + confirmed_at: number; + /** @description USD size of the trade (6 decimal places) */ + amount_usd: number; + /** @description Outcome shares traded (6 decimal places) */ + shares_amount: number; + /** @description Fee paid in USD (6 decimal places) */ + fee: number; + /** + * @description Trade direction + * @enum {string} + */ + side: "Buy" | "Sell"; + /** @description Outcome token price (0.0–1.0) */ + price: number; + /** @description Exchange identifier */ + exchange: string; + /** @description Trade type identifier */ + trade_type: string; + }; + /** @description Payload delivered when a trader places their first trade in a specific market (fires once per trader+market pair) */ + NewMarketPayload: { + /** @description Limit-order maker wallet address (lowercase) */ + trader: string; + /** @description Order filler wallet address (lowercase) */ + taker: string; + /** @description ERC-1155 outcome token ID */ + position_id: string; + /** @description Parent market condition ID */ + condition_id?: string | null; + /** @description Outcome name (e.g. "Yes", "No") */ + outcome?: string | null; + /** @description Outcome index: 0 = Yes/Up, 1 = No */ + outcome_index?: number | null; + /** @description Market question text */ + question?: string | null; + /** @description Market slug */ + market_slug?: string | null; + /** @description Parent event slug */ + event_slug?: string | null; + /** @description Unique trade identifier */ + trade_id: string; + /** @description Transaction hash */ + hash: string; + /** + * Format: int64 + * @description Block number + */ + block: number; + /** + * Format: int64 + * @description Block confirmation timestamp (Unix seconds) + */ + confirmed_at: number; + /** @description USD size of the trade (6 decimal places) */ + amount_usd: number; + /** @description Outcome shares traded (6 decimal places) */ + shares_amount: number; + /** @description Fee paid in USD (6 decimal places) */ + fee: number; + /** + * @description Trade direction + * @enum {string} + */ + side: "Buy" | "Sell"; + /** @description Outcome token price (0.0–1.0) */ + price: number; + /** @description Implied probability (0.0–1.0); null when outcome is unknown */ + probability?: number | null; + /** @description Exchange identifier */ + exchange: string; + /** @description Trade type identifier */ + trade_type: string; + }; + /** @description Payload delivered when a trade exceeds the configured size and probability thresholds */ + WhaleTradePayload: { + /** @description Limit-order maker wallet address (lowercase) */ + trader: string; + /** @description Order filler wallet address (lowercase) */ + taker: string; + /** @description ERC-1155 outcome token ID */ + position_id: string; + /** @description Parent market condition ID */ + condition_id?: string | null; + /** @description Outcome name (e.g. "Yes", "No") */ + outcome?: string | null; + /** @description Outcome index: 0 = Yes/Up, 1 = No */ + outcome_index?: number | null; + /** @description Market question text */ + question?: string | null; + /** @description Market slug */ + market_slug?: string | null; + /** @description Parent event slug */ + event_slug?: string | null; + /** @description Unique trade identifier */ + trade_id: string; + /** @description Transaction hash */ + hash: string; + /** + * Format: int64 + * @description Block number + */ + block: number; + /** + * Format: int64 + * @description Block confirmation timestamp (Unix seconds) + */ + confirmed_at: number; + /** @description USD size of the trade (6 decimal places) */ + amount_usd: number; + /** @description Outcome shares traded (6 decimal places) */ + shares_amount: number; + /** @description Fee paid in USD (6 decimal places) */ + fee: number; + /** + * @description Trade direction + * @enum {string} + */ + side: "Buy" | "Sell"; + /** @description Outcome token price (0.0–1.0) */ + price: number; + /** @description Implied probability (0.0–1.0); null when outcome is unknown */ + probability?: number | null; + /** @description Exchange identifier */ + exchange: string; + /** @description Trade type identifier */ + trade_type: string; + }; + /** @description Payload delivered on every order-filled trade */ + NewTradePayload: { + /** @description Limit-order maker wallet address (lowercase) */ + trader: string; + /** @description Order filler wallet address (lowercase) */ + taker: string; + /** @description ERC-1155 outcome token ID */ + position_id: string; + /** @description Parent market condition ID */ + condition_id?: string | null; + /** @description Outcome name (e.g. "Yes", "No") */ + outcome?: string | null; + /** @description Outcome index: 0 = Yes/Up, 1 = No */ + outcome_index?: number | null; + /** @description Market question text */ + question?: string | null; + /** @description Market slug */ + market_slug?: string | null; + /** @description Parent event slug */ + event_slug?: string | null; + /** @description Unique trade identifier */ + trade_id: string; + /** @description Transaction hash */ + hash: string; + /** + * Format: int64 + * @description Block number + */ + block: number; + /** + * Format: int64 + * @description Block confirmation timestamp (Unix seconds) + */ + confirmed_at: number; + /** @description USD size of the trade (6 decimal places) */ + amount_usd: number; + /** @description Outcome shares traded (6 decimal places) */ + shares_amount: number; + /** @description Fee paid in USD (6 decimal places) */ + fee: number; + /** + * @description Trade direction + * @enum {string} + */ + side: "Buy" | "Sell"; + /** @description Outcome token price (0.0–1.0) */ + price: number; + /** @description Implied probability (0.0–1.0); null when outcome is unknown */ + probability?: number | null; + /** @description Exchange identifier */ + exchange: string; + /** @description Trade type identifier */ + trade_type: string; + }; + /** @description Payload delivered when a trader's global PnL (across all markets) crosses a configured threshold */ + GlobalPnlPayload: { + /** @description Trader wallet address (lowercase) */ + trader?: string | null; + /** + * @description PnL aggregation window + * @enum {string} + */ + timeframe: "1d" | "7d" | "30d" | "lifetime"; + /** @description Realized PnL in USD (positive = profit, negative = loss) */ + realized_pnl_usd?: number | null; + /** + * Format: int64 + * @description Number of distinct events traded + */ + events_traded?: number | null; + /** + * Format: int64 + * @description Number of distinct markets traded + */ + markets_traded?: number | null; + /** + * Format: int64 + * @description Total buy transactions + */ + total_buys?: number | null; + /** + * Format: int64 + * @description Total sell transactions + */ + total_sells?: number | null; + /** + * Format: int64 + * @description Total redemption transactions + */ + total_redemptions?: number | null; + /** + * Format: int64 + * @description Total merge transactions + */ + total_merges?: number | null; + /** @description Total USD volume (buys + sells + redemptions + merges) */ + total_volume_usd?: number | null; + /** @description Total buy volume in USD */ + buy_volume_usd?: number | null; + /** @description Total sell volume in USD */ + sell_volume_usd?: number | null; + /** @description Total redemption volume in USD */ + redemption_volume_usd?: number | null; + /** @description Total merge volume in USD */ + merge_volume_usd?: number | null; + /** + * Format: int64 + * @description Number of markets where trader realised a profit + */ + markets_won?: number | null; + /** + * Format: int64 + * @description Number of markets where trader realised a loss + */ + markets_lost?: number | null; + /** @description Market win rate as a percentage (0.0–100.0) */ + market_win_rate_pct?: number | null; + /** @description Average PnL per market in USD */ + avg_pnl_per_market?: number | null; + /** @description Average PnL per trade in USD */ + avg_pnl_per_trade?: number | null; + /** @description Average hold time across all positions (seconds) */ + avg_hold_time_seconds?: number | null; + /** @description Total fees paid in USD */ + total_fees?: number | null; + /** @description Best single-trade PnL in USD */ + best_trade_pnl_usd?: number | null; + /** @description Condition ID of the best trade */ + best_trade_condition_id?: string | null; + /** + * Format: int64 + * @description Timestamp of the first trade (Unix seconds) + */ + first_trade_at?: number | null; + /** + * Format: int64 + * @description Timestamp of the most recent trade (Unix seconds) + */ + last_trade_at?: number | null; + }; + /** @description Payload delivered when a trader's per-market PnL crosses a configured threshold */ + MarketPnlPayload: { + /** @description Trader wallet address (lowercase) */ + trader?: string | null; + /** @description Market condition ID */ + condition_id?: string | null; + /** @description Parent event slug */ + event_slug?: string | null; + /** + * @description PnL aggregation window + * @enum {string} + */ + timeframe: "1d" | "7d" | "30d" | "lifetime"; + /** + * Format: int64 + * @description Number of distinct outcomes traded in this market + */ + outcomes_traded?: number | null; + /** Format: int64 */ + total_buys?: number | null; + /** Format: int64 */ + total_sells?: number | null; + /** Format: int64 */ + total_redemptions?: number | null; + /** Format: int64 */ + total_merges?: number | null; + /** @description Total buy volume in USD */ + buy_usd?: number | null; + /** @description Total sell volume in USD */ + sell_usd?: number | null; + /** @description Total redemption volume in USD */ + redemption_usd?: number | null; + /** @description Total merge volume in USD */ + merge_usd?: number | null; + /** @description Realized PnL in USD for this market */ + realized_pnl_usd?: number | null; + /** + * Format: int64 + * @description Number of outcomes with positive PnL + */ + winning_outcomes?: number | null; + /** @description Total fees paid in USD for this market */ + total_fees?: number | null; + /** + * Format: int64 + * @description Timestamp of first trade in market (Unix seconds) + */ + first_trade_at?: number | null; + /** + * Format: int64 + * @description Timestamp of most recent trade in market (Unix seconds) + */ + last_trade_at?: number | null; + }; + /** @description Payload delivered when a trader's per-event PnL crosses a configured threshold */ + EventPnlPayload: { + /** @description Trader wallet address (lowercase) */ + trader?: string | null; + /** @description Event slug */ + event_slug?: string | null; + /** + * @description PnL aggregation window + * @enum {string} + */ + timeframe: "1d" | "7d" | "30d" | "lifetime"; + /** + * Format: int64 + * @description Number of distinct markets traded in this event + */ + markets_traded?: number | null; + /** Format: int64 */ + outcomes_traded?: number | null; + /** Format: int64 */ + total_buys?: number | null; + /** Format: int64 */ + total_sells?: number | null; + /** Format: int64 */ + total_redemptions?: number | null; + /** Format: int64 */ + total_merges?: number | null; + /** @description Total volume in USD */ + total_volume_usd?: number | null; + buy_usd?: number | null; + sell_usd?: number | null; + redemption_usd?: number | null; + merge_usd?: number | null; + /** @description Realized PnL in USD for this event */ + realized_pnl_usd?: number | null; + /** Format: int64 */ + winning_markets?: number | null; + /** Format: int64 */ + losing_markets?: number | null; + total_fees?: number | null; + /** + * Format: int64 + * @description Unix seconds + */ + first_trade_at?: number | null; + /** + * Format: int64 + * @description Unix seconds + */ + last_trade_at?: number | null; + }; + /** @description Payload delivered when a market's volume or transaction metrics cross a configured threshold */ + ConditionMetricsPayload: { + /** @description Market condition ID */ + condition_id?: string | null; + /** @description Aggregation window (e.g. "1h", "24h") */ + timeframe?: string | null; + /** @description Total trading volume in USD for this timeframe */ + volume_usd?: number | null; + /** @description Total fees collected in USD */ + fees?: number | null; + /** + * Format: int64 + * @description Total number of transactions + */ + txns?: number | null; + /** + * Format: int64 + * @description Number of unique traders + */ + unique_traders?: number | null; + }; + /** @description Payload delivered when an event's aggregated volume or transaction metrics cross a configured threshold */ + EventMetricsPayload: { + /** @description Event slug */ + event_slug?: string | null; + /** @description Aggregation window (e.g. "1h", "24h") */ + timeframe?: string | null; + /** @description Total aggregated volume across all markets in the event (USD) */ + volume_usd?: number | null; + /** @description Total fees collected in USD */ + fees?: number | null; + /** + * Format: int64 + * @description Total number of transactions + */ + txns?: number | null; + /** + * Format: int64 + * @description Number of unique traders + */ + unique_traders?: number | null; + }; + /** @description Payload delivered when a position's volume or transaction metrics cross a configured threshold */ + PositionMetricsPayload: { + /** @description ERC-1155 outcome token ID */ + position_id?: string | null; + /** @description Outcome name (e.g. "Yes", "No") */ + outcome?: string | null; + /** + * Format: int16 + * @description Outcome index + */ + outcome_index?: number | null; + /** @description Aggregation window (e.g. "1h", "24h") */ + timeframe?: string | null; + /** @description Total trading volume in USD */ + volume_usd?: number | null; + /** @description Buy volume in USD */ + buy_volume_usd?: number | null; + /** @description Sell volume in USD */ + sell_volume_usd?: number | null; + /** @description Total fees in USD */ + fees?: number | null; + /** Format: int64 */ + txns?: number | null; + /** Format: int64 */ + buys?: number | null; + /** Format: int64 */ + sells?: number | null; + /** Format: int64 */ + unique_traders?: number | null; + price_open?: number | null; + price_close?: number | null; + price_high?: number | null; + price_low?: number | null; + probability_open?: number | null; + probability_close?: number | null; + probability_high?: number | null; + probability_low?: number | null; + }; + /** @description Payload delivered when a market's trading volume crosses a USD milestone in the specified timeframe */ + VolumeMilestonePayload: { + /** @description Market condition ID */ + condition_id: string; + /** @description Aggregation window that crossed the milestone (e.g. "1h", "24h") */ + timeframe: string; + /** @description The USD milestone amount that was crossed */ + milestone_usd: number; + /** @description Current volume at time of trigger (USD) */ + current_volume_usd: number; + /** @description Total fees in USD for this timeframe */ + fees: number; + /** + * Format: int64 + * @description Total transactions in this timeframe + */ + txns: number; + }; + /** @description Payload delivered when an event's aggregated trading volume crosses a USD milestone */ + EventVolumeMilestonePayload: { + /** @description Event slug */ + event_slug: string; + /** @description Aggregation window (e.g. "1h", "24h") */ + timeframe: string; + /** @description The USD milestone amount that was crossed */ + milestone_usd: number; + /** @description Current aggregated event volume at time of trigger (USD) */ + current_volume_usd: number; + /** @description Total fees in USD for this timeframe */ + fees: number; + /** + * Format: int64 + * @description Total transactions in this timeframe + */ + txns: number; + }; + /** @description Payload delivered when a position's trading volume crosses a USD milestone */ + PositionVolumeMilestonePayload: { + /** @description Parent market condition ID */ + condition_id?: string | null; + /** @description ERC-1155 outcome token ID */ + position_id: string; + /** @description Outcome name (e.g. "Yes", "No") */ + outcome?: string | null; + /** + * Format: int16 + * @description Outcome index + */ + outcome_index?: number | null; + /** @description Aggregation window (e.g. "1h", "24h") */ + timeframe: string; + /** @description The USD milestone amount that was crossed */ + milestone_usd: number; + /** @description Current position volume at time of trigger (USD) */ + current_volume_usd: number; + /** @description Buy volume in USD for this timeframe */ + buy_volume_usd: number; + /** @description Sell volume in USD for this timeframe */ + sell_volume_usd: number; + /** @description Total fees in USD */ + fees: number; + /** Format: int64 */ + txns: number; + /** Format: int64 */ + buys: number; + /** Format: int64 */ + sells: number; + }; + ProbabilitySpikePayload: { + /** @description Outcome token ID */ + position_id: string; + /** @description Market condition ID */ + condition_id?: string | null; + /** @description Event slug */ + event_slug?: string | null; + /** @description Outcome name (e.g. "Yes", "No") */ + outcome?: string | null; + /** + * Format: int16 + * @description Outcome index + */ + outcome_index?: number | null; + /** @description Probability at the start of the observation window (baseline snapshot, 0.0–1.0) */ + previous_probability: number; + /** @description Current probability that triggered the spike (0.0–1.0) */ + current_probability: number; + /** + * @description `"up"` = probability rising, `"down"` = probability falling + * @enum {string} + */ + spike_direction: "up" | "down"; + /** @description Percentage move that triggered this notification. Positive = up, negative = down. */ + spike_pct: number; + }; + PriceSpikePayload: { + /** @description Outcome token ID */ + position_id: string; + /** @description Market condition ID */ + condition_id?: string | null; + /** @description Event slug */ + event_slug?: string | null; + /** @description Outcome name (e.g. "Yes", "No") */ + outcome?: string | null; + /** + * Format: int16 + * @description Outcome index + */ + outcome_index?: number | null; + /** @description Price at the start of the observation window (baseline snapshot, 0.0–1.0) */ + previous_price: number; + /** @description Current price that triggered the spike (0.0–1.0) */ + current_price: number; + /** + * @description `"up"` = price rising, `"down"` = price falling + * @enum {string} + */ + spike_direction: "up" | "down"; + /** @description Percentage move that triggered this notification. Positive = up, negative = down. */ + spike_pct: number; + }; + /** @description Payload delivered when a market's volume has spiked since the last snapshot */ + MarketVolumeSpikePayload: { + /** @description Market condition ID */ + condition_id: string; + /** @description Aggregation window (e.g. "1h", "24h") */ + timeframe: string; + /** @description Current volume at the time of the spike (USD) */ + current_volume_usd: number; + /** @description Volume at the snapshot baseline (USD) */ + snapshot_volume_usd: number; + /** @description New volume since the snapshot that triggered this notification (USD) */ + delta_volume_usd: number; + /** @description Volume growth as a percentage of the snapshot (e.g. 200.0 means volume tripled) */ + spike_pct: number; + /** + * Format: int64 + * @description Total transactions in this timeframe + */ + txns: number; + /** @description Total fees in USD for this timeframe */ + fees: number; + }; + /** @description Payload delivered when an event's aggregated volume has spiked since the last snapshot */ + EventVolumeSpikePayload: { + /** @description Event slug */ + event_slug: string; + /** @description Aggregation window (e.g. "1h", "24h") */ + timeframe: string; + /** @description Current aggregated event volume at time of the spike (USD) */ + current_volume_usd: number; + /** @description Volume at the snapshot baseline (USD) */ + snapshot_volume_usd: number; + /** @description New volume since the snapshot that triggered this notification (USD) */ + delta_volume_usd: number; + /** @description Volume growth as a percentage of the snapshot (e.g. 200.0 means volume tripled) */ + spike_pct: number; + /** Format: int64 */ + txns: number; + fees: number; + }; + /** @description Payload delivered when a position's volume has spiked since the last snapshot */ + PositionVolumeSpikePayload: { + /** @description ERC-1155 outcome token ID */ + position_id: string; + /** @description Parent market condition ID */ + condition_id: string; + /** @description Outcome name (e.g. "Yes", "No") */ + outcome?: string | null; + /** Format: int16 */ + outcome_index?: number | null; + /** @description Aggregation window (e.g. "1h", "24h") */ + timeframe: string; + /** @description Current position volume at the time of the spike (USD) */ + current_volume_usd: number; + /** @description Volume at the snapshot baseline (USD) */ + snapshot_volume_usd: number; + /** @description New volume since the snapshot that triggered this notification (USD) */ + delta_volume_usd: number; + /** @description Volume growth as a percentage of the snapshot (e.g. 200.0 means volume tripled) */ + spike_pct: number; + /** Format: int64 */ + txns: number; + fees: number; + }; + /** @description Payload delivered when a trade occurs at a near-certain-outcome price */ + CloseToBondPayload: { + /** @description Limit-order maker wallet address (lowercase) */ + trader: string; + /** @description Order filler wallet address (lowercase) */ + taker: string; + /** @description ERC-1155 outcome token ID */ + position_id: string; + /** @description Parent market condition ID */ + condition_id?: string | null; + /** @description Outcome name (e.g. "Yes", "No") */ + outcome?: string | null; + /** @description 0 = Yes/Up, 1 = No */ + outcome_index?: number | null; + question?: string | null; + market_slug?: string | null; + event_slug?: string | null; + trade_id: string; + /** @description Transaction hash */ + hash: string; + /** Format: int64 */ + block: number; + /** + * Format: int64 + * @description Unix seconds + */ + confirmed_at: number; + /** @description USD size of the trade */ + amount_usd: number; + shares_amount: number; + /** @description Fee paid in USD */ + fee: number; + /** @enum {string} */ + side: "Buy" | "Sell"; + /** @description Price that triggered the notification (0.0–1.0) */ + price: number; + /** @description Implied probability (0.0–1.0) */ + probability?: number | null; + /** + * @description "high" when near YES (price ≥ threshold), "low" when near NO (price ≤ threshold) + * @enum {string} + */ + bond_side: "high" | "low"; + /** @description The probability threshold from the subscription filter that was breached */ + threshold: number; + }; + /** @description An outcome entry within a newly created market */ + MarketCreatedOutcome: { + /** @description Outcome index (0 = Yes, 1 = No) */ + index: number; + /** @description Outcome name (e.g. "Yes", "No") */ + name: string; + /** @description ERC-1155 position token ID for this outcome */ + position_id: string; + }; + /** @description Payload delivered when a new prediction market is detected on-chain and enriched with Gamma API metadata */ + MarketCreatedPayload: { + /** @description Condition ID (0x-prefixed hex, lowercase) */ + condition_id: string; + /** @description Market slug */ + market_slug: string; + /** @description Parent event slug */ + event_slug?: string | null; + /** @description Parent event ID */ + event_id?: string | null; + /** @description Parent event title */ + event_title?: string | null; + /** @description Series slug (for recurring markets) */ + series_slug?: string | null; + /** @description List of market outcomes with their position IDs */ + outcomes: components["schemas"]["MarketCreatedOutcome"][]; + /** @description Full market question text */ + question: string; + /** @description Short display title */ + title?: string | null; + /** @description Market description */ + description: string; + /** @description Market category (e.g. "Sports", "Politics") */ + category?: string | null; + /** @description Market tags */ + tags: string[]; + /** @description Cover image URL */ + image_url?: string | null; + /** @description Whether this is a neg-risk market */ + neg_risk: boolean; + }; + /** @description Payload delivered on every raw Chainlink price tick for a tracked crypto asset */ + AssetPriceTickPayload: { + /** + * @description Asset symbol + * @enum {string} + */ + symbol: "BTC" | "ETH" | "SOL" | "XRP" | "DOGE" | "BNB" | "HYPE"; + /** @description Current asset price in USD from the Chainlink feed */ + price: number; + /** + * Format: int64 + * @description Tick timestamp (milliseconds since Unix epoch) + */ + timestamp_ms: number; + }; + /** @description Payload delivered twice per candle — once on open and once on close. `close_price` is 0.0 on the "open" update. */ + AssetPriceWindowUpdatePayload: { + /** + * @description Asset symbol + * @enum {string} + */ + symbol: "BTC" | "ETH" | "SOL" | "XRP" | "DOGE" | "BNB" | "HYPE"; + /** + * @description Candle / window size + * @enum {string} + */ + variant: "5m" | "15m" | "1h" | "4h" | "1d" | "24h"; + /** + * Format: int64 + * @description Window start timestamp (milliseconds since Unix epoch) + */ + start_time: number; + /** + * Format: int64 + * @description Window end timestamp (milliseconds since Unix epoch) + */ + end_time: number; + /** @description Opening price at start_time (USD) */ + open_price: number; + /** @description Closing price at end_time (USD). 0.0 when update_type is "open" (not yet available). */ + close_price: number; + /** + * @description "open" when the candle opens, "close" when it closes with a confirmed price + * @enum {string} + */ + update_type: "open" | "close"; + }; + /** @description Subscription filters for the `trader_first_trade` event. All fields are optional. */ + TraderFirstTradeFilters: { + /** @description Only fire for trades by these wallet addresses (lowercase). Empty = all traders. */ + wallet_addresses?: string[]; + /** @description Restrict to trades in these markets. Empty = all markets. */ + condition_ids?: string[]; + /** @description Restrict to trades in markets belonging to these events. */ + event_slugs?: string[]; + /** @description Minimum trade size in USD. Omit to match all sizes. */ + min_usd_value?: number; + /** @description Only fire when the outcome probability is ≥ this value. */ + min_probability?: number; + /** @description Only fire when the outcome probability is ≤ this value. */ + max_probability?: number; + /** @description When `true`, suppress webhooks for short-term "updown" markets (event slugs containing `updown`). Default: `false`. */ + exclude_shortterm_markets?: boolean; + }; + /** @description Subscription filters for the `trader_new_market` event. All fields are optional. */ + TraderNewMarketFilters: { + /** @description Only fire for these wallet addresses (lowercase). Empty = all traders. */ + wallet_addresses?: string[]; + /** @description Restrict to these markets. */ + condition_ids?: string[]; + /** @description Restrict to markets belonging to these events. */ + event_slugs?: string[]; + /** @description When `true`, suppress webhooks for short-term "updown" markets. Default: `false`. */ + exclude_shortterm_markets?: boolean; + }; + /** @description Subscription filters for the `trader_whale_trade` event. All fields are optional. */ + TraderWhaleTradeFilters: { + /** @description Only fire for trades by these wallet addresses. Empty = all traders. */ + wallet_addresses?: string[]; + /** @description Restrict to these markets. */ + condition_ids?: string[]; + /** @description Restrict to markets belonging to these events. */ + event_slugs?: string[]; + /** @description Minimum trade size in USD. Defaults to 0 (matches all trades). */ + min_usd_value?: number; + /** @description Only fire when outcome probability is ≥ this value. */ + min_probability?: number; + /** @description Only fire when outcome probability is ≤ this value. */ + max_probability?: number; + /** @description When `true`, suppress webhooks for short-term "updown" markets. Default: `false`. */ + exclude_shortterm_markets?: boolean; + }; + /** @description Subscription filters for the `trader_new_trade` event. All fields are optional. */ + TraderNewTradeFilters: { + /** @description Only fire for trades by these wallet addresses. Empty = all traders. */ + wallet_addresses?: string[]; + /** @description Restrict to these markets. */ + condition_ids?: string[]; + /** @description Restrict to markets belonging to these events. */ + event_slugs?: string[]; + /** @description Minimum trade size in USD. Defaults to 0 (matches all trades). */ + min_usd_value?: number; + /** @description Only fire when outcome probability is ≥ this value. */ + min_probability?: number; + /** @description Only fire when outcome probability is ≤ this value. */ + max_probability?: number; + /** @description When `true`, suppress webhooks for short-term "updown" markets. Default: `false`. */ + exclude_shortterm_markets?: boolean; + }; + /** @description Subscription filters for the `trader_global_pnl` event. All fields are optional. */ + TraderGlobalPnlFilters: { + /** @description Track only these trader wallet addresses. Empty = all traders. */ + traders?: string[]; + /** @description Only fire when realized PnL ≥ this value (USD). Use negative values for loss thresholds. */ + min_realized_pnl_usd?: number; + /** @description Only fire when realized PnL ≤ this value (USD). */ + max_realized_pnl_usd?: number; + /** @description Only fire when total trading volume ≥ this value (USD). */ + min_volume_usd?: number; + /** @description Only fire when total trading volume ≤ this value (USD). */ + max_volume_usd?: number; + /** @description Only fire when buy volume ≥ this value (USD). */ + min_buy_usd?: number; + /** @description Only fire when sell volume ≥ this value (USD). */ + min_sell_volume_usd?: number; + /** @description Only fire when market win rate ≥ this percentage (0.0–100.0). */ + min_win_rate?: number; + /** + * Format: int64 + * @description Only fire when the trader has traded in ≥ this many markets. + */ + min_markets_traded?: number; + /** @description Restrict to these PnL windows. Empty = all windows. */ + timeframes?: ("1d" | "7d" | "30d" | "lifetime")[]; + }; + /** @description Subscription filters for the `trader_market_pnl` event. All fields are optional. */ + TraderMarketPnlFilters: { + /** @description Track only these trader wallet addresses. */ + traders?: string[]; + /** @description Restrict to these markets. */ + condition_ids?: string[]; + /** @description Restrict to markets in these events. */ + event_slugs?: string[]; + /** @description Only fire when per-market realized PnL ≥ this value (USD). */ + min_realized_pnl_usd?: number; + /** @description Only fire when per-market realized PnL ≤ this value (USD). */ + max_realized_pnl_usd?: number; + /** @description Only fire when total volume (buy + sell + redemption + merge) ≥ this value (USD). */ + min_volume_usd?: number; + /** @description Only fire when total volume ≤ this value (USD). */ + max_volume_usd?: number; + /** @description Only fire when buy volume in the market ≥ this value (USD). */ + min_buy_usd?: number; + /** @description Only fire when sell volume in the market ≥ this value (USD). */ + min_sell_volume_usd?: number; + /** @description Restrict to these PnL windows. */ + timeframes?: ("1d" | "7d" | "30d" | "lifetime")[]; + /** @description When `true`, suppress webhooks for short-term "updown" markets. Default: `false`. */ + exclude_shortterm_markets?: boolean; + }; + /** @description Subscription filters for the `trader_event_pnl` event. All fields are optional. */ + TraderEventPnlFilters: { + /** @description Track only these trader wallet addresses. */ + traders?: string[]; + /** @description Restrict to these events. */ + event_slugs?: string[]; + /** @description Only fire when per-event realized PnL ≥ this value (USD). */ + min_realized_pnl_usd?: number; + /** @description Only fire when per-event realized PnL ≤ this value (USD). */ + max_realized_pnl_usd?: number; + /** @description Only fire when total event volume ≥ this value (USD). */ + min_volume_usd?: number; + /** @description Only fire when total event volume ≤ this value (USD). */ + max_volume_usd?: number; + /** @description Only fire when buy volume within the event ≥ this value (USD). */ + min_buy_usd?: number; + /** @description Only fire when sell volume within the event ≥ this value (USD). */ + min_sell_volume_usd?: number; + /** + * Format: int64 + * @description Only fire when the trader has traded in ≥ this many markets within the event. + */ + min_markets_traded?: number; + /** @description Restrict to these PnL windows. */ + timeframes?: ("1d" | "7d" | "30d" | "lifetime")[]; + /** @description When `true`, suppress webhooks for short-term "updown" markets. Default: `false`. */ + exclude_shortterm_markets?: boolean; + }; + /** @description Subscription filters for the `condition_metrics` event. All fields are optional. */ + MarketMetricsFilters: { + /** @description Restrict to these markets. Empty = all markets. */ + condition_ids?: string[]; + /** @description Restrict to markets in these events. */ + event_slugs?: string[]; + /** @description Restrict to these aggregation windows. Empty = all windows. */ + timeframes?: ("1m" | "5m" | "30m" | "1h" | "6h" | "24h" | "7d" | "30d")[]; + /** @description Only fire when volume ≥ this value (USD). */ + min_volume_usd?: number; + /** @description Only fire when volume ≤ this value (USD). */ + max_volume_usd?: number; + /** + * Format: int64 + * @description Only fire when transaction count ≥ this value. + */ + min_txns?: number; + /** + * Format: int64 + * @description Only fire when unique trader count ≥ this value. + */ + min_unique_traders?: number; + /** @description Only fire when total fees ≥ this value (USD). */ + min_fees?: number; + }; + /** @description Subscription filters for the `event_metrics` event. All fields are optional. */ + EventMetricsFilters: { + /** @description Restrict to these events. Empty = all events. */ + event_slugs?: string[]; + /** @description Restrict to these aggregation windows. */ + timeframes?: ("1m" | "5m" | "30m" | "1h" | "6h" | "24h" | "7d" | "30d")[]; + /** @description Only fire when aggregated event volume ≥ this value (USD). */ + min_volume_usd?: number; + max_volume_usd?: number; + /** Format: int64 */ + min_txns?: number; + /** Format: int64 */ + min_unique_traders?: number; + min_fees?: number; + /** @description When `true`, suppress webhooks for short-term "updown" markets. Default: `false`. */ + exclude_shortterm_markets?: boolean; + }; + /** @description Subscription filters for the `position_metrics` event. All fields are optional. */ + PositionMetricsFilters: { + /** @description Restrict to these outcome token IDs. */ + position_ids?: string[]; + /** @description Restrict to positions within these markets. */ + condition_ids?: string[]; + /** @description Restrict to positions with these outcome names (e.g. ["Yes", "No"]). */ + outcomes?: string[]; + /** @description Restrict to these aggregation windows. */ + timeframes?: ("1m" | "5m" | "30m" | "1h" | "6h" | "24h" | "7d" | "30d")[]; + /** @description Only fire when position volume ≥ this value (USD). */ + min_volume_usd?: number; + max_volume_usd?: number; + min_buy_usd?: number; + min_sell_volume_usd?: number; + /** Format: int64 */ + min_txns?: number; + /** Format: int64 */ + min_unique_traders?: number; + /** @description Only fire when price change % ≥ this value. */ + min_price_change_pct?: number; + /** @description Only fire when probability change % ≥ this value. */ + min_probability_change_pct?: number; + min_fees?: number; + }; + /** @description Subscription filters for the `market_volume_milestone` event. */ + MarketVolumeMilestoneFilters: { + /** @description **Required.** Aggregation windows to monitor (e.g. ["1h", "24h"]). */ + timeframes: ("1m" | "5m" | "30m" | "1h" | "6h" | "24h" | "7d" | "30d")[]; + /** @description Restrict to these markets. Empty = all markets. */ + condition_ids?: string[]; + /** @description Specific USD milestones to trigger on (e.g. [10000, 100000, 1000000]). Empty = all milestones. */ + milestone_amounts?: number[]; + }; + /** @description Subscription filters for the `event_volume_milestone` event. */ + EventVolumeMilestoneFilters: { + /** @description **Required.** Aggregation windows to monitor. */ + timeframes: ("1m" | "5m" | "30m" | "1h" | "6h" | "24h" | "7d" | "30d")[]; + /** @description Restrict to these events. */ + event_slugs?: string[]; + /** @description Specific USD milestones to trigger on. */ + milestone_amounts?: number[]; + /** @description When `true`, suppress webhooks for short-term "updown" markets. Default: `false`. */ + exclude_shortterm_markets?: boolean; + }; + /** @description Subscription filters for the `position_volume_milestone` event. */ + PositionVolumeMilestoneFilters: { + /** @description **Required.** Aggregation windows to monitor. */ + timeframes: ("1m" | "5m" | "30m" | "1h" | "6h" | "24h" | "7d" | "30d")[]; + /** @description Restrict to these outcome token IDs. */ + position_ids?: string[]; + /** @description Restrict to positions within these markets. */ + condition_ids?: string[]; + /** @description Specific USD milestones to trigger on. */ + milestone_amounts?: number[]; + }; + /** @description Subscription filters for the `probability_spike` event. */ + ProbabilitySpikeFilters: { + /** @description Restrict to specific outcome token IDs. Empty = all positions. */ + position_ids?: string[]; + /** @description Restrict to specific market condition IDs. Empty = all markets. */ + condition_ids?: string[]; + /** @description Restrict to specific events. Empty = all events. */ + event_slugs?: string[]; + /** @description Restrict to these outcome names (e.g. ["Yes", "No"]). */ + outcomes?: string[]; + /** @description Minimum probability percentage move to trigger (e.g. `10` for a 10% move). */ + min_probability_change_pct?: number; + /** + * @description `"up"` = probability rising only (default when omitted), `"down"` = falling only, `"both"` = either direction. + * @enum {string} + */ + spike_direction?: "up" | "down" | "both"; + /** @description Observation window in seconds. The first trade in each window sets the reference price; subsequent trades are compared to it. E.g. `60` detects moves that occur within 60 seconds. */ + window_secs?: number; + /** @description When `true`, suppress webhooks for short-term "updown" markets. Default: `false`. */ + exclude_shortterm_markets?: boolean; + }; + /** @description Subscription filters for the `price_spike` event. */ + PriceSpikeFilters: { + /** @description Restrict to specific outcome token IDs. Empty = all positions. */ + position_ids?: string[]; + /** @description Restrict to specific market condition IDs. Empty = all markets. */ + condition_ids?: string[]; + /** @description Restrict to specific events. Empty = all events. */ + event_slugs?: string[]; + /** @description Restrict to these outcome names (e.g. ["Yes", "No"]). */ + outcomes?: string[]; + /** @description Minimum price percentage move to trigger (e.g. `10` for a 10% move). */ + min_price_change_pct?: number; + /** + * @description `"up"` = price rising only (default when omitted), `"down"` = falling only, `"both"` = either direction. + * @enum {string} + */ + spike_direction?: "up" | "down" | "both"; + /** @description Observation window in seconds. The first trade in each window sets the reference price; subsequent trades are compared to it. E.g. `60` detects moves that occur within 60 seconds. */ + window_secs?: number; + /** @description When `true`, suppress webhooks for short-term "updown" markets. Default: `false`. */ + exclude_shortterm_markets?: boolean; + }; + /** @description Subscription filters for the `market_volume_spike` event. `spike_ratio` is required. */ + MarketVolumeSpikeFilters: { + /** @description **Required.** Multiplier threshold (must be > 1.0). Fires when current volume >= snapshot × ratio. The snapshot is set automatically on first data and resets after each fire. */ + spike_ratio: number; + /** @description Force snapshot reset after this many seconds (max 600 / 10 minutes). */ + window_secs?: number; + /** @description Restrict to these markets. Empty = all markets. */ + condition_ids?: string[]; + /** @description Restrict to these aggregation windows. Empty = all windows. */ + timeframes?: ("1m" | "5m" | "30m" | "1h" | "6h" | "1d" | "24h" | "7d" | "30d")[]; + }; + /** @description Subscription filters for the `event_volume_spike` event. `spike_ratio` is required. */ + EventVolumeSpikeFilters: { + /** @description **Required.** Multiplier threshold (must be > 1.0). Fires when current volume >= snapshot × ratio. */ + spike_ratio: number; + /** @description Force snapshot reset after this many seconds (max 600 / 10 minutes). */ + window_secs?: number; + /** @description Restrict to these events. */ + event_slugs?: string[]; + /** @description Restrict to these aggregation windows. */ + timeframes?: ("1m" | "5m" | "30m" | "1h" | "6h" | "1d" | "24h" | "7d" | "30d")[]; + /** @description When `true`, suppress webhooks for short-term "updown" markets. Default: `false`. */ + exclude_shortterm_markets?: boolean; + }; + /** @description Subscription filters for the `position_volume_spike` event. `spike_ratio` is required. */ + PositionVolumeSpikeFilters: { + /** @description **Required.** Multiplier threshold (must be > 1.0). Fires when current volume >= snapshot × ratio. */ + spike_ratio: number; + /** @description Force snapshot reset after this many seconds (max 600 / 10 minutes). */ + window_secs?: number; + /** @description Restrict to these outcome token IDs. */ + position_ids?: string[]; + /** @description Restrict to positions within these markets. */ + condition_ids?: string[]; + /** @description Restrict to these outcome names. */ + outcomes?: string[]; + /** @description Restrict to these aggregation windows. */ + timeframes?: ("1m" | "5m" | "30m" | "1h" | "6h" | "1d" | "24h" | "7d" | "30d")[]; + }; + /** @description Subscription filters for the `close_to_bond` event. At least one of `min_probability` or `max_probability` is required. */ + CloseToBondFilters: { + /** @description Trigger when the YES outcome price is ≥ this value (e.g. 0.95 for 95% certainty). At least one of `min_probability` or `max_probability` must be set. */ + min_probability?: number; + /** @description Trigger when the YES outcome price is ≤ this value (e.g. 0.05 for near-certain NO). */ + max_probability?: number; + /** @description Restrict to these markets. */ + condition_ids?: string[]; + /** @description Restrict to these outcome token IDs. */ + position_ids?: string[]; + /** @description Restrict to markets in these events. */ + event_slugs?: string[]; + /** @description Restrict to these outcome names (e.g. ["Yes", "No"]). */ + outcomes?: string[]; + /** @description Restrict by outcome index. 0 = Yes/Up, 1 = No. Position 0 usually represents the Up/Yes side in binary markets. */ + position_outcome_indices?: number[]; + /** @description When `true`, suppress webhooks for short-term "updown" markets. Default: `false`. */ + exclude_shortterm_markets?: boolean; + } | unknown | unknown; + /** @description Subscription filters for the `market_created` event. All fields are optional. */ + MarketCreatedFilters: { + /** @description Restrict to markets with these tags or category names (case-insensitive match). */ + tags?: string[]; + /** @description Restrict to these specific markets. */ + condition_ids?: string[]; + /** @description Restrict to markets belonging to these events. */ + event_slugs?: string[]; + /** @description When `true`, suppress webhooks for short-term "updown" markets (event slugs containing `updown`). Default: `false`. */ + exclude_shortterm_markets?: boolean; + }; + /** @description Subscription filters for the `asset_price_tick` event. All fields are optional. */ + AssetPriceTickFilters: { + /** @description Restrict to these crypto assets. Empty = all assets. */ + asset_symbols?: ("BTC" | "ETH" | "SOL" | "XRP" | "DOGE" | "BNB" | "HYPE")[]; + }; + /** @description Subscription filters for the `asset_price_window_update` event. All fields are optional. */ + AssetPriceWindowUpdateFilters: { + /** @description Restrict to these crypto assets. Empty = all assets. */ + asset_symbols?: ("BTC" | "ETH" | "SOL" | "XRP" | "DOGE" | "BNB" | "HYPE")[]; + /** @description Restrict to these candle sizes. Empty = all sizes. */ + timeframes?: ("5m" | "15m" | "1h" | "4h" | "1d" | "24h")[]; + }; + /** + * @description All alert event types supported by both HTTP webhooks and the alerts WebSocket. + * @enum {string} + */ + WsAlertEventType: "trader_first_trade" | "trader_new_market" | "trader_whale_trade" | "trader_new_trade" | "trader_global_pnl" | "trader_market_pnl" | "trader_event_pnl" | "condition_metrics" | "event_metrics" | "position_metrics" | "market_volume_milestone" | "event_volume_milestone" | "position_volume_milestone" | "probability_spike" | "price_spike" | "market_volume_spike" | "event_volume_spike" | "position_volume_spike" | "close_to_bond" | "market_created" | "asset_price_tick" | "asset_price_window_update"; + /** @description Server acknowledgement for a successful alert subscription. */ + WsAlertSubscribedResponse: { + /** @enum {string} */ + op: "subscribed"; + event: components["schemas"]["WsAlertEventType"]; + /** Format: uuid */ + subscription_id: string; + }; + /** @description Server acknowledgement for a successful alert unsubscription. */ + WsAlertUnsubscribedResponse: { + /** @enum {string} */ + op: "unsubscribed"; + event: components["schemas"]["WsAlertEventType"]; + }; + /** @description Error returned by the alerts WebSocket when a message is invalid or a subscription request fails. */ + WsAlertErrorResponse: { + error: string; + }; + WsAlertTraderFirstTradeSubscribeMessage: { + /** @enum {string} */ + op: "subscribe"; + /** @enum {string} */ + event: "trader_first_trade"; + } & components["schemas"]["TraderFirstTradeFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "trader_first_trade"; + }; + WsAlertTraderFirstTradeUnsubscribeMessage: { + /** @enum {string} */ + op: "unsubscribe"; + /** @enum {string} */ + event: "trader_first_trade"; + } & components["schemas"]["TraderFirstTradeFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "trader_first_trade"; + }; + /** + * @description Pushed `trader_first_trade` alert. The `data` payload matches the corresponding HTTP webhook payload schema. + * @example { + * "event": "trader_first_trade", + * "timestamp": 1743500000000, + * "data": { + * "trader": "0x0000000000000000000000000000000000000000", + * "taker": "0x0000000000000000000000000000000000000000", + * "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", + * "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + * "outcome": "Yes", + * "outcome_index": 0, + * "question": "Will this test webhook fire correctly?", + * "market_slug": "test-market-0000000000", + * "event_slug": "test-event-0000000000", + * "trade_id": "00000000-0000-0000-0000-000000000000", + * "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + * "block": 0, + * "confirmed_at": 1700000000, + * "amount_usd": 125, + * "shares_amount": 250, + * "fee": 0.125, + * "side": "Buy", + * "price": 0.5, + * "exchange": "polymarket", + * "trade_type": "OrderFilled" + * } + * } + */ + WsAlertTraderFirstTradeEvent: { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "trader_first_trade"; + /** + * Format: int64 + * @description Unix timestamp in milliseconds + */ + timestamp: number; + data: components["schemas"]["FirstTradePayload"]; + }; + WsAlertTraderNewMarketSubscribeMessage: { + /** @enum {string} */ + op: "subscribe"; + /** @enum {string} */ + event: "trader_new_market"; + } & components["schemas"]["TraderNewMarketFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "trader_new_market"; + }; + WsAlertTraderNewMarketUnsubscribeMessage: { + /** @enum {string} */ + op: "unsubscribe"; + /** @enum {string} */ + event: "trader_new_market"; + } & components["schemas"]["TraderNewMarketFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "trader_new_market"; + }; + /** + * @description Pushed `trader_new_market` alert. The `data` payload matches the corresponding HTTP webhook payload schema. + * @example { + * "event": "trader_new_market", + * "timestamp": 1743500000000, + * "data": { + * "trader": "0x0000000000000000000000000000000000000000", + * "taker": "0x0000000000000000000000000000000000000000", + * "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", + * "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + * "outcome": "Yes", + * "outcome_index": 0, + * "question": "Will this test webhook fire correctly?", + * "market_slug": "test-market-0000000000", + * "event_slug": "test-event-0000000000", + * "trade_id": "00000000-0000-0000-0000-000000000000", + * "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + * "block": 0, + * "confirmed_at": 1700000000, + * "amount_usd": 125, + * "shares_amount": 250, + * "fee": 0.125, + * "side": "Buy", + * "price": 0.5, + * "probability": 0.5, + * "exchange": "polymarket", + * "trade_type": "OrderFilled" + * } + * } + */ + WsAlertTraderNewMarketEvent: { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "trader_new_market"; + /** + * Format: int64 + * @description Unix timestamp in milliseconds + */ + timestamp: number; + data: components["schemas"]["NewMarketPayload"]; + }; + WsAlertTraderWhaleTradeSubscribeMessage: { + /** @enum {string} */ + op: "subscribe"; + /** @enum {string} */ + event: "trader_whale_trade"; + } & components["schemas"]["TraderWhaleTradeFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "trader_whale_trade"; + }; + WsAlertTraderWhaleTradeUnsubscribeMessage: { + /** @enum {string} */ + op: "unsubscribe"; + /** @enum {string} */ + event: "trader_whale_trade"; + } & components["schemas"]["TraderWhaleTradeFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "trader_whale_trade"; + }; + /** + * @description Pushed `trader_whale_trade` alert. The `data` payload matches the corresponding HTTP webhook payload schema. + * @example { + * "event": "trader_whale_trade", + * "timestamp": 1743500000000, + * "data": { + * "trader": "0x0000000000000000000000000000000000000000", + * "taker": "0x0000000000000000000000000000000000000000", + * "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", + * "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + * "outcome": "Yes", + * "outcome_index": 0, + * "question": "Will this test webhook fire correctly?", + * "market_slug": "test-market-0000000000", + * "event_slug": "test-event-0000000000", + * "trade_id": "00000000-0000-0000-0000-000000000000", + * "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + * "block": 0, + * "confirmed_at": 1700000000, + * "amount_usd": 125, + * "shares_amount": 250, + * "fee": 0.125, + * "side": "Buy", + * "price": 0.5, + * "probability": 0.5, + * "exchange": "polymarket", + * "trade_type": "OrderFilled" + * } + * } + */ + WsAlertTraderWhaleTradeEvent: { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "trader_whale_trade"; + /** + * Format: int64 + * @description Unix timestamp in milliseconds + */ + timestamp: number; + data: components["schemas"]["WhaleTradePayload"]; + }; + WsAlertTraderNewTradeSubscribeMessage: { + /** @enum {string} */ + op: "subscribe"; + /** @enum {string} */ + event: "trader_new_trade"; + } & components["schemas"]["TraderNewTradeFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "trader_new_trade"; + }; + WsAlertTraderNewTradeUnsubscribeMessage: { + /** @enum {string} */ + op: "unsubscribe"; + /** @enum {string} */ + event: "trader_new_trade"; + } & components["schemas"]["TraderNewTradeFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "trader_new_trade"; + }; + /** + * @description Pushed `trader_new_trade` alert. The `data` payload matches the corresponding HTTP webhook payload schema. + * @example { + * "event": "trader_new_trade", + * "timestamp": 1743500000000, + * "data": { + * "trader": "0x0000000000000000000000000000000000000000", + * "taker": "0x0000000000000000000000000000000000000000", + * "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", + * "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + * "outcome": "Yes", + * "outcome_index": 0, + * "question": "Will this test webhook fire correctly?", + * "market_slug": "test-market-0000000000", + * "event_slug": "test-event-0000000000", + * "trade_id": "00000000-0000-0000-0000-000000000000", + * "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + * "block": 0, + * "confirmed_at": 1700000000, + * "amount_usd": 25, + * "shares_amount": 50, + * "fee": 0.025, + * "side": "Buy", + * "price": 0.5, + * "probability": 0.5, + * "exchange": "polymarket", + * "trade_type": "OrderFilled" + * } + * } + */ + WsAlertTraderNewTradeEvent: { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "trader_new_trade"; + /** + * Format: int64 + * @description Unix timestamp in milliseconds + */ + timestamp: number; + data: components["schemas"]["NewTradePayload"]; + }; + WsAlertTraderGlobalPnlSubscribeMessage: { + /** @enum {string} */ + op: "subscribe"; + /** @enum {string} */ + event: "trader_global_pnl"; + } & components["schemas"]["TraderGlobalPnlFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "trader_global_pnl"; + }; + WsAlertTraderGlobalPnlUnsubscribeMessage: { + /** @enum {string} */ + op: "unsubscribe"; + /** @enum {string} */ + event: "trader_global_pnl"; + } & components["schemas"]["TraderGlobalPnlFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "trader_global_pnl"; + }; + /** + * @description Pushed `trader_global_pnl` alert. The `data` payload matches the corresponding HTTP webhook payload schema. + * @example { + * "event": "trader_global_pnl", + * "timestamp": 1743500000000, + * "data": { + * "trader": "0x0000000000000000000000000000000000000000", + * "timeframe": "7d", + * "realized_pnl_usd": 250, + * "events_traded": 3, + * "markets_traded": 5, + * "total_buys": 12, + * "total_sells": 8, + * "total_redemptions": 1, + * "total_merges": 0, + * "total_volume_usd": 1500, + * "buy_volume_usd": 900, + * "sell_volume_usd": 600, + * "redemption_volume_usd": 50, + * "merge_volume_usd": 0, + * "markets_won": 3, + * "markets_lost": 2, + * "market_win_rate_pct": 60, + * "avg_pnl_per_market": 50, + * "avg_pnl_per_trade": 12.5, + * "avg_hold_time_seconds": 86400, + * "total_fees": 7.5, + * "best_trade_pnl_usd": 180, + * "best_trade_condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + * "first_trade_at": 1700000000, + * "last_trade_at": 1700000000 + * } + * } + */ + WsAlertTraderGlobalPnlEvent: { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "trader_global_pnl"; + /** + * Format: int64 + * @description Unix timestamp in milliseconds + */ + timestamp: number; + data: components["schemas"]["GlobalPnlPayload"]; + }; + WsAlertTraderMarketPnlSubscribeMessage: { + /** @enum {string} */ + op: "subscribe"; + /** @enum {string} */ + event: "trader_market_pnl"; + } & components["schemas"]["TraderMarketPnlFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "trader_market_pnl"; + }; + WsAlertTraderMarketPnlUnsubscribeMessage: { + /** @enum {string} */ + op: "unsubscribe"; + /** @enum {string} */ + event: "trader_market_pnl"; + } & components["schemas"]["TraderMarketPnlFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "trader_market_pnl"; + }; + /** + * @description Pushed `trader_market_pnl` alert. The `data` payload matches the corresponding HTTP webhook payload schema. + * @example { + * "event": "trader_market_pnl", + * "timestamp": 1743500000000, + * "data": { + * "trader": "0x0000000000000000000000000000000000000000", + * "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + * "event_slug": "test-event-0000000000", + * "timeframe": "7d", + * "outcomes_traded": 2, + * "total_buys": 4, + * "total_sells": 3, + * "total_redemptions": 1, + * "total_merges": 0, + * "buy_usd": 300, + * "sell_usd": 200, + * "redemption_usd": 50, + * "merge_usd": 0, + * "realized_pnl_usd": 100, + * "winning_outcomes": 1, + * "total_fees": 2.5, + * "first_trade_at": 1700000000, + * "last_trade_at": 1700000000 + * } + * } + */ + WsAlertTraderMarketPnlEvent: { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "trader_market_pnl"; + /** + * Format: int64 + * @description Unix timestamp in milliseconds + */ + timestamp: number; + data: components["schemas"]["MarketPnlPayload"]; + }; + WsAlertTraderEventPnlSubscribeMessage: { + /** @enum {string} */ + op: "subscribe"; + /** @enum {string} */ + event: "trader_event_pnl"; + } & components["schemas"]["TraderEventPnlFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "trader_event_pnl"; + }; + WsAlertTraderEventPnlUnsubscribeMessage: { + /** @enum {string} */ + op: "unsubscribe"; + /** @enum {string} */ + event: "trader_event_pnl"; + } & components["schemas"]["TraderEventPnlFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "trader_event_pnl"; + }; + /** + * @description Pushed `trader_event_pnl` alert. The `data` payload matches the corresponding HTTP webhook payload schema. + * @example { + * "event": "trader_event_pnl", + * "timestamp": 1743500000000, + * "data": { + * "trader": "0x0000000000000000000000000000000000000000", + * "event_slug": "test-event-0000000000", + * "timeframe": "7d", + * "markets_traded": 2, + * "outcomes_traded": 3, + * "total_buys": 6, + * "total_sells": 4, + * "total_redemptions": 1, + * "total_merges": 0, + * "total_volume_usd": 800, + * "buy_usd": 480, + * "sell_usd": 320, + * "redemption_usd": 50, + * "merge_usd": 0, + * "realized_pnl_usd": 150, + * "winning_markets": 1, + * "losing_markets": 1, + * "total_fees": 4, + * "first_trade_at": 1700000000, + * "last_trade_at": 1700000000 + * } + * } + */ + WsAlertTraderEventPnlEvent: { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "trader_event_pnl"; + /** + * Format: int64 + * @description Unix timestamp in milliseconds + */ + timestamp: number; + data: components["schemas"]["EventPnlPayload"]; + }; + WsAlertConditionMetricsSubscribeMessage: { + /** @enum {string} */ + op: "subscribe"; + /** @enum {string} */ + event: "condition_metrics"; + } & components["schemas"]["MarketMetricsFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "condition_metrics"; + }; + WsAlertConditionMetricsUnsubscribeMessage: { + /** @enum {string} */ + op: "unsubscribe"; + /** @enum {string} */ + event: "condition_metrics"; + } & components["schemas"]["MarketMetricsFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "condition_metrics"; + }; + /** + * @description Pushed `condition_metrics` alert. The `data` payload matches the corresponding HTTP webhook payload schema. + * @example { + * "event": "condition_metrics", + * "timestamp": 1743500000000, + * "data": { + * "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + * "timeframe": "1h", + * "volume_usd": 50000, + * "fees": 250, + * "txns": 320, + * "unique_traders": 85 + * } + * } + */ + WsAlertConditionMetricsEvent: { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "condition_metrics"; + /** + * Format: int64 + * @description Unix timestamp in milliseconds + */ + timestamp: number; + data: components["schemas"]["ConditionMetricsPayload"]; + }; + WsAlertEventMetricsSubscribeMessage: { + /** @enum {string} */ + op: "subscribe"; + /** @enum {string} */ + event: "event_metrics"; + } & components["schemas"]["EventMetricsFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "event_metrics"; + }; + WsAlertEventMetricsUnsubscribeMessage: { + /** @enum {string} */ + op: "unsubscribe"; + /** @enum {string} */ + event: "event_metrics"; + } & components["schemas"]["EventMetricsFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "event_metrics"; + }; + /** + * @description Pushed `event_metrics` alert. The `data` payload matches the corresponding HTTP webhook payload schema. + * @example { + * "event": "event_metrics", + * "timestamp": 1743500000000, + * "data": { + * "event_slug": "test-event-0000000000", + * "timeframe": "1h", + * "volume_usd": 120000, + * "fees": 600, + * "txns": 740, + * "unique_traders": 210 + * } + * } + */ + WsAlertEventMetricsEvent: { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "event_metrics"; + /** + * Format: int64 + * @description Unix timestamp in milliseconds + */ + timestamp: number; + data: components["schemas"]["EventMetricsPayload"]; + }; + WsAlertPositionMetricsSubscribeMessage: { + /** @enum {string} */ + op: "subscribe"; + /** @enum {string} */ + event: "position_metrics"; + } & components["schemas"]["PositionMetricsFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "position_metrics"; + }; + WsAlertPositionMetricsUnsubscribeMessage: { + /** @enum {string} */ + op: "unsubscribe"; + /** @enum {string} */ + event: "position_metrics"; + } & components["schemas"]["PositionMetricsFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "position_metrics"; + }; + /** + * @description Pushed `position_metrics` alert. The `data` payload matches the corresponding HTTP webhook payload schema. + * @example { + * "event": "position_metrics", + * "timestamp": 1743500000000, + * "data": { + * "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", + * "outcome": "Yes", + * "outcome_index": 0, + * "timeframe": "1h", + * "volume_usd": 25000, + * "buy_volume_usd": 15000, + * "sell_volume_usd": 10000, + * "fees": 125, + * "txns": 160, + * "buys": 95, + * "sells": 65, + * "unique_traders": 48, + * "price_open": 0.48, + * "price_close": 0.52, + * "price_high": 0.55, + * "price_low": 0.46, + * "probability_open": 0.48, + * "probability_close": 0.52, + * "probability_high": 0.55, + * "probability_low": 0.46 + * } + * } + */ + WsAlertPositionMetricsEvent: { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "position_metrics"; + /** + * Format: int64 + * @description Unix timestamp in milliseconds + */ + timestamp: number; + data: components["schemas"]["PositionMetricsPayload"]; + }; + WsAlertMarketVolumeMilestoneSubscribeMessage: { + /** @enum {string} */ + op: "subscribe"; + /** @enum {string} */ + event: "market_volume_milestone"; + } & components["schemas"]["MarketVolumeMilestoneFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "market_volume_milestone"; + }; + WsAlertMarketVolumeMilestoneUnsubscribeMessage: { + /** @enum {string} */ + op: "unsubscribe"; + /** @enum {string} */ + event: "market_volume_milestone"; + } & components["schemas"]["MarketVolumeMilestoneFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "market_volume_milestone"; + }; + /** + * @description Pushed `market_volume_milestone` alert. The `data` payload matches the corresponding HTTP webhook payload schema. + * @example { + * "event": "market_volume_milestone", + * "timestamp": 1743500000000, + * "data": { + * "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + * "timeframe": "24h", + * "milestone_usd": 100000, + * "current_volume_usd": 100125, + * "fees": 500, + * "txns": 650 + * } + * } + */ + WsAlertMarketVolumeMilestoneEvent: { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "market_volume_milestone"; + /** + * Format: int64 + * @description Unix timestamp in milliseconds + */ + timestamp: number; + data: components["schemas"]["VolumeMilestonePayload"]; + }; + WsAlertEventVolumeMilestoneSubscribeMessage: { + /** @enum {string} */ + op: "subscribe"; + /** @enum {string} */ + event: "event_volume_milestone"; + } & components["schemas"]["EventVolumeMilestoneFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "event_volume_milestone"; + }; + WsAlertEventVolumeMilestoneUnsubscribeMessage: { + /** @enum {string} */ + op: "unsubscribe"; + /** @enum {string} */ + event: "event_volume_milestone"; + } & components["schemas"]["EventVolumeMilestoneFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "event_volume_milestone"; + }; + /** + * @description Pushed `event_volume_milestone` alert. The `data` payload matches the corresponding HTTP webhook payload schema. + * @example { + * "event": "event_volume_milestone", + * "timestamp": 1743500000000, + * "data": { + * "event_slug": "test-event-0000000000", + * "timeframe": "24h", + * "milestone_usd": 500000, + * "current_volume_usd": 500250, + * "fees": 2500, + * "txns": 3200 + * } + * } + */ + WsAlertEventVolumeMilestoneEvent: { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "event_volume_milestone"; + /** + * Format: int64 + * @description Unix timestamp in milliseconds + */ + timestamp: number; + data: components["schemas"]["EventVolumeMilestonePayload"]; + }; + WsAlertPositionVolumeMilestoneSubscribeMessage: { + /** @enum {string} */ + op: "subscribe"; + /** @enum {string} */ + event: "position_volume_milestone"; + } & components["schemas"]["PositionVolumeMilestoneFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "position_volume_milestone"; + }; + WsAlertPositionVolumeMilestoneUnsubscribeMessage: { + /** @enum {string} */ + op: "unsubscribe"; + /** @enum {string} */ + event: "position_volume_milestone"; + } & components["schemas"]["PositionVolumeMilestoneFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "position_volume_milestone"; + }; + /** + * @description Pushed `position_volume_milestone` alert. The `data` payload matches the corresponding HTTP webhook payload schema. + * @example { + * "event": "position_volume_milestone", + * "timestamp": 1743500000000, + * "data": { + * "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + * "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", + * "outcome": "Yes", + * "outcome_index": 0, + * "timeframe": "24h", + * "milestone_usd": 50000, + * "current_volume_usd": 50125, + * "buy_volume_usd": 30000, + * "sell_volume_usd": 20000, + * "fees": 250, + * "txns": 320, + * "buys": 190, + * "sells": 130 + * } + * } + */ + WsAlertPositionVolumeMilestoneEvent: { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "position_volume_milestone"; + /** + * Format: int64 + * @description Unix timestamp in milliseconds + */ + timestamp: number; + data: components["schemas"]["PositionVolumeMilestonePayload"]; + }; + WsAlertProbabilitySpikeSubscribeMessage: { + /** @enum {string} */ + op: "subscribe"; + /** @enum {string} */ + event: "probability_spike"; + } & components["schemas"]["ProbabilitySpikeFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "probability_spike"; + }; + WsAlertProbabilitySpikeUnsubscribeMessage: { + /** @enum {string} */ + op: "unsubscribe"; + /** @enum {string} */ + event: "probability_spike"; + } & components["schemas"]["ProbabilitySpikeFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "probability_spike"; + }; + /** + * @description Pushed `probability_spike` alert. The `data` payload matches the corresponding HTTP webhook payload schema. + * @example { + * "event": "probability_spike", + * "timestamp": 1743500000000, + * "data": { + * "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", + * "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + * "event_slug": "test-event-0000000000", + * "outcome": "Yes", + * "outcome_index": 0, + * "previous_probability": 0.4, + * "current_probability": 0.5, + * "spike_direction": "up", + * "spike_pct": 25 + * } + * } + */ + WsAlertProbabilitySpikeEvent: { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "probability_spike"; + /** + * Format: int64 + * @description Unix timestamp in milliseconds + */ + timestamp: number; + data: components["schemas"]["ProbabilitySpikePayload"]; + }; + WsAlertPriceSpikeSubscribeMessage: { + /** @enum {string} */ + op: "subscribe"; + /** @enum {string} */ + event: "price_spike"; + } & components["schemas"]["PriceSpikeFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "price_spike"; + }; + WsAlertPriceSpikeUnsubscribeMessage: { + /** @enum {string} */ + op: "unsubscribe"; + /** @enum {string} */ + event: "price_spike"; + } & components["schemas"]["PriceSpikeFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "price_spike"; + }; + /** + * @description Pushed `price_spike` alert. The `data` payload matches the corresponding HTTP webhook payload schema. + * @example { + * "event": "price_spike", + * "timestamp": 1743500000000, + * "data": { + * "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", + * "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + * "event_slug": "test-event-0000000000", + * "outcome": "Yes", + * "outcome_index": 0, + * "previous_price": 0.4, + * "current_price": 0.5, + * "spike_direction": "up", + * "spike_pct": 25 + * } + * } + */ + WsAlertPriceSpikeEvent: { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "price_spike"; + /** + * Format: int64 + * @description Unix timestamp in milliseconds + */ + timestamp: number; + data: components["schemas"]["PriceSpikePayload"]; + }; + WsAlertMarketVolumeSpikeSubscribeMessage: { + /** @enum {string} */ + op: "subscribe"; + /** @enum {string} */ + event: "market_volume_spike"; + } & components["schemas"]["MarketVolumeSpikeFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "market_volume_spike"; + }; + WsAlertMarketVolumeSpikeUnsubscribeMessage: { + /** @enum {string} */ + op: "unsubscribe"; + /** @enum {string} */ + event: "market_volume_spike"; + } & components["schemas"]["MarketVolumeSpikeFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "market_volume_spike"; + }; + /** + * @description Pushed `market_volume_spike` alert. The `data` payload matches the corresponding HTTP webhook payload schema. + * @example { + * "event": "market_volume_spike", + * "timestamp": 1743500000000, + * "data": { + * "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + * "timeframe": "1h", + * "current_volume_usd": 32000, + * "snapshot_volume_usd": 10000, + * "delta_volume_usd": 22000, + * "spike_pct": 220, + * "txns": 480, + * "fees": 160 + * } + * } + */ + WsAlertMarketVolumeSpikeEvent: { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "market_volume_spike"; + /** + * Format: int64 + * @description Unix timestamp in milliseconds + */ + timestamp: number; + data: components["schemas"]["MarketVolumeSpikePayload"]; + }; + WsAlertEventVolumeSpikeSubscribeMessage: { + /** @enum {string} */ + op: "subscribe"; + /** @enum {string} */ + event: "event_volume_spike"; + } & components["schemas"]["EventVolumeSpikeFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "event_volume_spike"; + }; + WsAlertEventVolumeSpikeUnsubscribeMessage: { + /** @enum {string} */ + op: "unsubscribe"; + /** @enum {string} */ + event: "event_volume_spike"; + } & components["schemas"]["EventVolumeSpikeFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "event_volume_spike"; + }; + /** + * @description Pushed `event_volume_spike` alert. The `data` payload matches the corresponding HTTP webhook payload schema. + * @example { + * "event": "event_volume_spike", + * "timestamp": 1743500000000, + * "data": { + * "event_slug": "test-event-0000000000", + * "timeframe": "1h", + * "current_volume_usd": 140000, + * "snapshot_volume_usd": 50000, + * "delta_volume_usd": 90000, + * "spike_pct": 180, + * "txns": 1100, + * "fees": 700 + * } + * } + */ + WsAlertEventVolumeSpikeEvent: { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "event_volume_spike"; + /** + * Format: int64 + * @description Unix timestamp in milliseconds + */ + timestamp: number; + data: components["schemas"]["EventVolumeSpikePayload"]; + }; + WsAlertPositionVolumeSpikeSubscribeMessage: { + /** @enum {string} */ + op: "subscribe"; + /** @enum {string} */ + event: "position_volume_spike"; + } & components["schemas"]["PositionVolumeSpikeFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "position_volume_spike"; + }; + WsAlertPositionVolumeSpikeUnsubscribeMessage: { + /** @enum {string} */ + op: "unsubscribe"; + /** @enum {string} */ + event: "position_volume_spike"; + } & components["schemas"]["PositionVolumeSpikeFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "position_volume_spike"; + }; + /** + * @description Pushed `position_volume_spike` alert. The `data` payload matches the corresponding HTTP webhook payload schema. + * @example { + * "event": "position_volume_spike", + * "timestamp": 1743500000000, + * "data": { + * "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", + * "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + * "outcome": "Yes", + * "outcome_index": 0, + * "timeframe": "1h", + * "current_volume_usd": 20500, + * "snapshot_volume_usd": 5000, + * "delta_volume_usd": 15500, + * "spike_pct": 310, + * "txns": 240, + * "fees": 102.5 + * } + * } + */ + WsAlertPositionVolumeSpikeEvent: { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "position_volume_spike"; + /** + * Format: int64 + * @description Unix timestamp in milliseconds + */ + timestamp: number; + data: components["schemas"]["PositionVolumeSpikePayload"]; + }; + WsAlertCloseToBondSubscribeMessage: ({ + /** @enum {string} */ + op: "subscribe"; + /** @enum {string} */ + event: "close_to_bond"; + } & components["schemas"]["CloseToBondFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "close_to_bond"; + }) | unknown | unknown; + WsAlertCloseToBondUnsubscribeMessage: ({ + /** @enum {string} */ + op: "unsubscribe"; + /** @enum {string} */ + event: "close_to_bond"; + } & components["schemas"]["CloseToBondFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "close_to_bond"; + }) | unknown | unknown; + /** + * @description Pushed `close_to_bond` alert. The `data` payload matches the corresponding HTTP webhook payload schema. + * @example { + * "event": "close_to_bond", + * "timestamp": 1743500000000, + * "data": { + * "trader": "0x0000000000000000000000000000000000000000", + * "taker": "0x0000000000000000000000000000000000000000", + * "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", + * "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + * "outcome": "Yes", + * "outcome_index": 0, + * "question": "Will this test webhook fire correctly?", + * "market_slug": "test-market-0000000000", + * "event_slug": "test-event-0000000000", + * "trade_id": "00000000-0000-0000-0000-000000000000", + * "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + * "block": 0, + * "confirmed_at": 1700000000, + * "amount_usd": 500, + * "shares_amount": 515.46, + * "fee": 2.5, + * "side": "Buy", + * "price": 0.97, + * "probability": 0.97, + * "bond_side": "high", + * "threshold": 0.95 + * } + * } + */ + WsAlertCloseToBondEvent: { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "close_to_bond"; + /** + * Format: int64 + * @description Unix timestamp in milliseconds + */ + timestamp: number; + data: components["schemas"]["CloseToBondPayload"]; + }; + WsAlertMarketCreatedSubscribeMessage: { + /** @enum {string} */ + op: "subscribe"; + /** @enum {string} */ + event: "market_created"; + } & components["schemas"]["MarketCreatedFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "market_created"; + }; + WsAlertMarketCreatedUnsubscribeMessage: { + /** @enum {string} */ + op: "unsubscribe"; + /** @enum {string} */ + event: "market_created"; + } & components["schemas"]["MarketCreatedFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "market_created"; + }; + /** + * @description Pushed `market_created` alert. The `data` payload matches the corresponding HTTP webhook payload schema. + * @example { + * "event": "market_created", + * "timestamp": 1743500000000, + * "data": { + * "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", + * "market_slug": "test-market-0000000000", + * "event_slug": "test-event-0000000000", + * "event_id": null, + * "event_title": "Test Event 0000", + * "series_slug": null, + * "outcomes": [ + * { + * "index": 0, + * "name": "Yes", + * "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656" + * }, + * { + * "index": 1, + * "name": "No", + * "position_id": "0" + * } + * ], + * "question": "Will this test webhook fire correctly?", + * "title": "Test Market 0000", + * "description": "A test market for webhook payload verification.", + * "category": "Crypto", + * "tags": [ + * "test", + * "crypto" + * ], + * "image_url": null, + * "neg_risk": false + * } + * } + */ + WsAlertMarketCreatedEvent: { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "market_created"; + /** + * Format: int64 + * @description Unix timestamp in milliseconds + */ + timestamp: number; + data: components["schemas"]["MarketCreatedPayload"]; + }; + WsAlertAssetPriceTickSubscribeMessage: { + /** @enum {string} */ + op: "subscribe"; + /** @enum {string} */ + event: "asset_price_tick"; + } & components["schemas"]["AssetPriceTickFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "asset_price_tick"; + }; + WsAlertAssetPriceTickUnsubscribeMessage: { + /** @enum {string} */ + op: "unsubscribe"; + /** @enum {string} */ + event: "asset_price_tick"; + } & components["schemas"]["AssetPriceTickFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "asset_price_tick"; + }; + /** + * @description Pushed `asset_price_tick` alert. The `data` payload matches the corresponding HTTP webhook payload schema. + * @example { + * "event": "asset_price_tick", + * "timestamp": 1743500000000, + * "data": { + * "symbol": "BTC", + * "price": 65000, + * "timestamp_ms": 1700000000000 + * } + * } + */ + WsAlertAssetPriceTickEvent: { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "asset_price_tick"; + /** + * Format: int64 + * @description Unix timestamp in milliseconds + */ + timestamp: number; + data: components["schemas"]["AssetPriceTickPayload"]; + }; + WsAlertAssetPriceWindowUpdateSubscribeMessage: { + /** @enum {string} */ + op: "subscribe"; + /** @enum {string} */ + event: "asset_price_window_update"; + } & components["schemas"]["AssetPriceWindowUpdateFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "asset_price_window_update"; + }; + WsAlertAssetPriceWindowUpdateUnsubscribeMessage: { + /** @enum {string} */ + op: "unsubscribe"; + /** @enum {string} */ + event: "asset_price_window_update"; + } & components["schemas"]["AssetPriceWindowUpdateFilters"] & { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "asset_price_window_update"; + }; + /** + * @description Pushed `asset_price_window_update` alert. The `data` payload matches the corresponding HTTP webhook payload schema. + * @example { + * "event": "asset_price_window_update", + * "timestamp": 1743500000000, + * "data": { + * "symbol": "BTC", + * "variant": "1h", + * "start_time": 1700000000000, + * "end_time": 1700003600000, + * "open_price": 64800, + * "close_price": 65200, + * "update_type": "close" + * } + * } + */ + WsAlertAssetPriceWindowUpdateEvent: { + /** + * @description discriminator enum property added by openapi-typescript + * @enum {string} + */ + event: "asset_price_window_update"; + /** + * Format: int64 + * @description Unix timestamp in milliseconds + */ + timestamp: number; + data: components["schemas"]["AssetPriceWindowUpdatePayload"]; + }; + /** @description Typed subscribe request for the alerts WebSocket. The request shape depends on `event` and reuses the matching webhook filter schema. */ + WsAlertSubscribeMessage: components["schemas"]["WsAlertTraderFirstTradeSubscribeMessage"] | components["schemas"]["WsAlertTraderNewMarketSubscribeMessage"] | components["schemas"]["WsAlertTraderWhaleTradeSubscribeMessage"] | components["schemas"]["WsAlertTraderNewTradeSubscribeMessage"] | components["schemas"]["WsAlertTraderGlobalPnlSubscribeMessage"] | components["schemas"]["WsAlertTraderMarketPnlSubscribeMessage"] | components["schemas"]["WsAlertTraderEventPnlSubscribeMessage"] | components["schemas"]["WsAlertConditionMetricsSubscribeMessage"] | components["schemas"]["WsAlertEventMetricsSubscribeMessage"] | components["schemas"]["WsAlertPositionMetricsSubscribeMessage"] | components["schemas"]["WsAlertMarketVolumeMilestoneSubscribeMessage"] | components["schemas"]["WsAlertEventVolumeMilestoneSubscribeMessage"] | components["schemas"]["WsAlertPositionVolumeMilestoneSubscribeMessage"] | components["schemas"]["WsAlertProbabilitySpikeSubscribeMessage"] | components["schemas"]["WsAlertPriceSpikeSubscribeMessage"] | components["schemas"]["WsAlertMarketVolumeSpikeSubscribeMessage"] | components["schemas"]["WsAlertEventVolumeSpikeSubscribeMessage"] | components["schemas"]["WsAlertPositionVolumeSpikeSubscribeMessage"] | components["schemas"]["WsAlertCloseToBondSubscribeMessage"] | components["schemas"]["WsAlertMarketCreatedSubscribeMessage"] | components["schemas"]["WsAlertAssetPriceTickSubscribeMessage"] | components["schemas"]["WsAlertAssetPriceWindowUpdateSubscribeMessage"]; + /** @description Typed unsubscribe request for the alerts WebSocket. The request shape depends on `event` and must match the original subscription filters. */ + WsAlertUnsubscribeMessage: components["schemas"]["WsAlertTraderFirstTradeUnsubscribeMessage"] | components["schemas"]["WsAlertTraderNewMarketUnsubscribeMessage"] | components["schemas"]["WsAlertTraderWhaleTradeUnsubscribeMessage"] | components["schemas"]["WsAlertTraderNewTradeUnsubscribeMessage"] | components["schemas"]["WsAlertTraderGlobalPnlUnsubscribeMessage"] | components["schemas"]["WsAlertTraderMarketPnlUnsubscribeMessage"] | components["schemas"]["WsAlertTraderEventPnlUnsubscribeMessage"] | components["schemas"]["WsAlertConditionMetricsUnsubscribeMessage"] | components["schemas"]["WsAlertEventMetricsUnsubscribeMessage"] | components["schemas"]["WsAlertPositionMetricsUnsubscribeMessage"] | components["schemas"]["WsAlertMarketVolumeMilestoneUnsubscribeMessage"] | components["schemas"]["WsAlertEventVolumeMilestoneUnsubscribeMessage"] | components["schemas"]["WsAlertPositionVolumeMilestoneUnsubscribeMessage"] | components["schemas"]["WsAlertProbabilitySpikeUnsubscribeMessage"] | components["schemas"]["WsAlertPriceSpikeUnsubscribeMessage"] | components["schemas"]["WsAlertMarketVolumeSpikeUnsubscribeMessage"] | components["schemas"]["WsAlertEventVolumeSpikeUnsubscribeMessage"] | components["schemas"]["WsAlertPositionVolumeSpikeUnsubscribeMessage"] | components["schemas"]["WsAlertCloseToBondUnsubscribeMessage"] | components["schemas"]["WsAlertMarketCreatedUnsubscribeMessage"] | components["schemas"]["WsAlertAssetPriceTickUnsubscribeMessage"] | components["schemas"]["WsAlertAssetPriceWindowUpdateUnsubscribeMessage"]; + /** @description Typed pushed-event envelope for the alerts WebSocket. The `data` payload depends on `event` and matches the corresponding HTTP webhook payload schema. */ + WsAlertEventPayload: components["schemas"]["WsAlertTraderFirstTradeEvent"] | components["schemas"]["WsAlertTraderNewMarketEvent"] | components["schemas"]["WsAlertTraderWhaleTradeEvent"] | components["schemas"]["WsAlertTraderNewTradeEvent"] | components["schemas"]["WsAlertTraderGlobalPnlEvent"] | components["schemas"]["WsAlertTraderMarketPnlEvent"] | components["schemas"]["WsAlertTraderEventPnlEvent"] | components["schemas"]["WsAlertConditionMetricsEvent"] | components["schemas"]["WsAlertEventMetricsEvent"] | components["schemas"]["WsAlertPositionMetricsEvent"] | components["schemas"]["WsAlertMarketVolumeMilestoneEvent"] | components["schemas"]["WsAlertEventVolumeMilestoneEvent"] | components["schemas"]["WsAlertPositionVolumeMilestoneEvent"] | components["schemas"]["WsAlertProbabilitySpikeEvent"] | components["schemas"]["WsAlertPriceSpikeEvent"] | components["schemas"]["WsAlertMarketVolumeSpikeEvent"] | components["schemas"]["WsAlertEventVolumeSpikeEvent"] | components["schemas"]["WsAlertPositionVolumeSpikeEvent"] | components["schemas"]["WsAlertCloseToBondEvent"] | components["schemas"]["WsAlertMarketCreatedEvent"] | components["schemas"]["WsAlertAssetPriceTickEvent"] | components["schemas"]["WsAlertAssetPriceWindowUpdateEvent"]; + }; + responses: never; + parameters: never; + requestBodies: never; + headers: never; + pathItems: never; +} +export type $defs = Record; +export type operations = Record; + +export interface WsAlertSubscribeMap { + trader_first_trade: components["schemas"]["WsAlertTraderFirstTradeSubscribeMessage"]; + trader_new_market: components["schemas"]["WsAlertTraderNewMarketSubscribeMessage"]; + trader_whale_trade: components["schemas"]["WsAlertTraderWhaleTradeSubscribeMessage"]; + trader_new_trade: components["schemas"]["WsAlertTraderNewTradeSubscribeMessage"]; + trader_global_pnl: components["schemas"]["WsAlertTraderGlobalPnlSubscribeMessage"]; + trader_market_pnl: components["schemas"]["WsAlertTraderMarketPnlSubscribeMessage"]; + trader_event_pnl: components["schemas"]["WsAlertTraderEventPnlSubscribeMessage"]; + condition_metrics: components["schemas"]["WsAlertConditionMetricsSubscribeMessage"]; + event_metrics: components["schemas"]["WsAlertEventMetricsSubscribeMessage"]; + position_metrics: components["schemas"]["WsAlertPositionMetricsSubscribeMessage"]; + market_volume_milestone: components["schemas"]["WsAlertMarketVolumeMilestoneSubscribeMessage"]; + event_volume_milestone: components["schemas"]["WsAlertEventVolumeMilestoneSubscribeMessage"]; + position_volume_milestone: components["schemas"]["WsAlertPositionVolumeMilestoneSubscribeMessage"]; + probability_spike: components["schemas"]["WsAlertProbabilitySpikeSubscribeMessage"]; + price_spike: components["schemas"]["WsAlertPriceSpikeSubscribeMessage"]; + market_volume_spike: components["schemas"]["WsAlertMarketVolumeSpikeSubscribeMessage"]; + event_volume_spike: components["schemas"]["WsAlertEventVolumeSpikeSubscribeMessage"]; + position_volume_spike: components["schemas"]["WsAlertPositionVolumeSpikeSubscribeMessage"]; + close_to_bond: components["schemas"]["WsAlertCloseToBondSubscribeMessage"]; + market_created: components["schemas"]["WsAlertMarketCreatedSubscribeMessage"]; + asset_price_tick: components["schemas"]["WsAlertAssetPriceTickSubscribeMessage"]; + asset_price_window_update: components["schemas"]["WsAlertAssetPriceWindowUpdateSubscribeMessage"]; +} + +export interface WsAlertEventDataMap { + trader_first_trade: components["schemas"]["FirstTradePayload"]; + trader_new_market: components["schemas"]["NewMarketPayload"]; + trader_whale_trade: components["schemas"]["WhaleTradePayload"]; + trader_new_trade: components["schemas"]["NewTradePayload"]; + trader_global_pnl: components["schemas"]["GlobalPnlPayload"]; + trader_market_pnl: components["schemas"]["MarketPnlPayload"]; + trader_event_pnl: components["schemas"]["EventPnlPayload"]; + condition_metrics: components["schemas"]["ConditionMetricsPayload"]; + event_metrics: components["schemas"]["EventMetricsPayload"]; + position_metrics: components["schemas"]["PositionMetricsPayload"]; + market_volume_milestone: components["schemas"]["VolumeMilestonePayload"]; + event_volume_milestone: components["schemas"]["EventVolumeMilestonePayload"]; + position_volume_milestone: components["schemas"]["PositionVolumeMilestonePayload"]; + probability_spike: components["schemas"]["ProbabilitySpikePayload"]; + price_spike: components["schemas"]["PriceSpikePayload"]; + market_volume_spike: components["schemas"]["MarketVolumeSpikePayload"]; + event_volume_spike: components["schemas"]["EventVolumeSpikePayload"]; + position_volume_spike: components["schemas"]["PositionVolumeSpikePayload"]; + close_to_bond: components["schemas"]["CloseToBondPayload"]; + market_created: components["schemas"]["MarketCreatedPayload"]; + asset_price_tick: components["schemas"]["AssetPriceTickPayload"]; + asset_price_window_update: components["schemas"]["AssetPriceWindowUpdatePayload"]; +} + +export type WsAlertEventName = keyof WsAlertSubscribeMap; diff --git a/src/generated/ws.ts b/src/generated/ws.ts index 5b8ac10..34f4ef6 100644 --- a/src/generated/ws.ts +++ b/src/generated/ws.ts @@ -2,63 +2,101 @@ export type paths = Record; export type webhooks = Record; export interface components { schemas: { - /** @description Subscription filters for the `asset_price_window_update` event. All fields are optional. */ - AssetPriceWindowUpdateFilters: { - /** @description Restrict to these crypto assets. Empty = all assets. */ - asset_symbols?: ("BTC" | "ETH" | "SOL" | "XRP" | "DOGE" | "BNB" | "HYPE")[]; - /** @description Restrict to these candle sizes. Empty = all sizes. */ - timeframes?: ("5m" | "15m" | "1h" | "4h" | "1d" | "24h")[]; - }; - /** @description Subscription filters for the `asset_price_tick` event. All fields are optional. */ - AssetPriceTickFilters: { - /** @description Restrict to these crypto assets. Empty = all assets. */ - asset_symbols?: ("BTC" | "ETH" | "SOL" | "XRP" | "DOGE" | "BNB" | "HYPE")[]; + /** @description Server-pushed CLOB reward change event. Envelope type: "clob_rewards_update". */ + ClobRewardsUpdateEvent: { + /** + * @description Type of change + * @enum {string} + */ + event_type?: "added" | "removed" | "updated"; + /** @description Affected market condition ID */ + condition_id?: string; + /** @description Full reward state (null for 'removed' events) */ + reward?: { + condition_id?: string; + rewards_config?: { + id?: number; + /** @description Reward token address (e.g. USDC) */ + asset_address?: string; + /** Format: date */ + start_date?: string; + /** Format: date */ + end_date?: string; + /** @description Daily reward rate in USDC */ + rate_per_day?: number; + /** @description Cumulative rewards distributed */ + total_rewards?: number; + }[]; + /** @description Max spread to qualify for rewards */ + rewards_max_spread?: number | null; + /** @description Min order size to qualify for rewards */ + rewards_min_size?: number | null; + /** @description Native (non-sponsored) daily rate */ + native_daily_rate?: number | null; + /** @description Sponsored daily rate */ + sponsored_daily_rate?: number | null; + /** @description Combined daily rate (native + sponsored) */ + total_daily_rate?: number | null; + /** @description Number of sponsors */ + sponsors_count?: number | null; + } | null; + /** @description Unix timestamp in milliseconds */ + timestamp_ms?: number; }; - /** @description Subscription filters for the `market_created` event. All fields are optional. */ - MarketCreatedFilters: { - /** @description Restrict to markets with these tags or category names (case-insensitive match). */ - tags?: string[]; - /** @description Restrict to these specific markets. */ + /** @description Server acknowledgement for a CLOB rewards subscription. Envelope type: "clob_rewards_stream_subscribe_response". */ + ClobRewardsSubscribeResponse: { + /** @description Accepted condition IDs */ condition_ids?: string[]; - /** @description Restrict to markets belonging to these events. */ - event_slugs?: string[]; - /** @description When `true`, suppress webhooks for short-term "updown" markets (event slugs containing `updown`). Default: `false`. */ - exclude_shortterm_markets?: boolean; + /** @description Whether subscribed to all changes */ + subscribe_all?: boolean; + /** @description Filter values that were rejected */ + rejected?: string[]; }; - /** @description Subscription filters for the `close_to_bond` event. At least one of `min_probability` or `max_probability` is required. */ - CloseToBondFilters: { - /** @description Trigger when the YES outcome price is ≥ this value (e.g. 0.95 for 95% certainty). At least one of `min_probability` or `max_probability` must be set. */ - min_probability?: number; - /** @description Trigger when the YES outcome price is ≤ this value (e.g. 0.05 for near-certain NO). */ - max_probability?: number; - /** @description Restrict to these markets. */ - condition_ids?: string[]; - /** @description Restrict to these outcome token IDs. */ - position_ids?: string[]; - /** @description Restrict to markets in these events. */ - event_slugs?: string[]; - /** @description Restrict to these outcome names (e.g. ["Yes", "No"]). */ - outcomes?: string[]; - /** @description Restrict by outcome index. 0 = Yes/Up, 1 = No. Position 0 usually represents the Up/Yes side in binary markets. */ - position_outcome_indices?: number[]; - /** @description When `true`, suppress webhooks for short-term "updown" markets. Default: `false`. */ - exclude_shortterm_markets?: boolean; - } | unknown | unknown; - /** @description Subscription filters for the `position_volume_spike` event. `spike_ratio` is required. */ - PositionVolumeSpikeFilters: { - /** @description **Required.** Multiplier threshold (must be > 1.0). Fires when current volume >= snapshot × ratio. */ - spike_ratio: number; - /** @description Force snapshot reset after this many seconds (max 600 / 10 minutes). */ - window_secs?: number; - /** @description Restrict to these outcome token IDs. */ - position_ids?: string[]; - /** @description Restrict to positions within these markets. */ + /** @description Subscribe to CLOB reward changes. Either provide specific condition_ids or set subscribe_all to true. */ + ClobRewardsSubscribeMessage: { + /** @enum {string} */ + action: "subscribe" | "unsubscribe_all"; + /** @description Condition IDs to watch for reward changes. */ condition_ids?: string[]; - /** @description Restrict to these outcome names. */ - outcomes?: string[]; - /** @description Restrict to these aggregation windows. */ - timeframes?: ("1m" | "5m" | "30m" | "1h" | "6h" | "1d" | "24h" | "7d" | "30d")[]; + /** @description If true, receive ALL reward changes across all markets. Overrides condition_ids. */ + subscribe_all?: boolean; + }; + /** @description Server-pushed event: full CLOB orderbook snapshot for an outcome token. Envelope type: "order_book_update". Delivered whenever the book changes for a subscribed condition or position. */ + OrderBookUpdateEvent: { + /** @description Hex token ID (position / outcome token) */ + asset_id: string; + /** @description Condition ID (hex) */ + market: string; + /** @description Bid levels sorted best-first (highest price first) */ + bids: components["schemas"]["OrderBookLevel"][]; + /** @description Ask levels sorted best-first (lowest price first) */ + asks: components["schemas"]["OrderBookLevel"][]; + /** + * Format: int64 + * @description Unix milliseconds from CLOB message + */ + timestamp: number; + /** @description Orderbook content hash — identical hash means no change */ + hash: string; + /** @description Best bid price (0–1) */ + best_bid?: number | null; + /** @description Best ask price (0–1) */ + best_ask?: number | null; + /** @description (best_bid + best_ask) / 2 */ + mid_price?: number | null; + /** @description best_ask − best_bid */ + spread?: number | null; + /** @description Total USD value of all bid levels */ + bid_liquidity_usd?: number | null; + /** @description Total USD value of all ask levels */ + ask_liquidity_usd?: number | null; + /** @description Number of bid price levels */ + bid_levels?: number | null; + /** @description Number of ask price levels */ + ask_levels?: number | null; }; + /** @description A single price level: [price_string, size_string] */ + OrderBookLevel: string[]; /** @description Subscribe to the trades stream. No filters = subscribe to all trades. */ TradesStreamSubscribeMessage: { /** @enum {string} */ @@ -872,2581 +910,6 @@ export interface components { /** @description Filter values that were rejected (invalid format or limit exceeded) */ rejected?: string[]; }; - /** @description A single price level: [price_string, size_string] */ - OrderBookLevel: string[]; - /** @description Server-pushed event: full CLOB orderbook snapshot for an outcome token. Envelope type: "order_book_update". Delivered whenever the book changes for a subscribed condition or position. */ - OrderBookUpdateEvent: { - /** @description Hex token ID (position / outcome token) */ - asset_id: string; - /** @description Condition ID (hex) */ - market: string; - /** @description Bid levels sorted best-first (highest price first) */ - bids: components["schemas"]["OrderBookLevel"][]; - /** @description Ask levels sorted best-first (lowest price first) */ - asks: components["schemas"]["OrderBookLevel"][]; - /** - * Format: int64 - * @description Unix milliseconds from CLOB message - */ - timestamp: number; - /** @description Orderbook content hash — identical hash means no change */ - hash: string; - /** @description Best bid price (0–1) */ - best_bid?: number | null; - /** @description Best ask price (0–1) */ - best_ask?: number | null; - /** @description (best_bid + best_ask) / 2 */ - mid_price?: number | null; - /** @description best_ask − best_bid */ - spread?: number | null; - /** @description Total USD value of all bid levels */ - bid_liquidity_usd?: number | null; - /** @description Total USD value of all ask levels */ - ask_liquidity_usd?: number | null; - /** @description Number of bid price levels */ - bid_levels?: number | null; - /** @description Number of ask price levels */ - ask_levels?: number | null; - }; - /** @description Subscribe to CLOB reward changes. Either provide specific condition_ids or set subscribe_all to true. */ - ClobRewardsSubscribeMessage: { - /** @enum {string} */ - action: "subscribe" | "unsubscribe_all"; - /** @description Condition IDs to watch for reward changes. */ - condition_ids?: string[]; - /** @description If true, receive ALL reward changes across all markets. Overrides condition_ids. */ - subscribe_all?: boolean; - }; - /** @description Server acknowledgement for a CLOB rewards subscription. Envelope type: "clob_rewards_stream_subscribe_response". */ - ClobRewardsSubscribeResponse: { - /** @description Accepted condition IDs */ - condition_ids?: string[]; - /** @description Whether subscribed to all changes */ - subscribe_all?: boolean; - /** @description Filter values that were rejected */ - rejected?: string[]; - }; - /** @description Server-pushed CLOB reward change event. Envelope type: "clob_rewards_update". */ - ClobRewardsUpdateEvent: { - /** - * @description Type of change - * @enum {string} - */ - event_type?: "added" | "removed" | "updated"; - /** @description Affected market condition ID */ - condition_id?: string; - /** @description Full reward state (null for 'removed' events) */ - reward?: { - condition_id?: string; - rewards_config?: { - id?: number; - /** @description Reward token address (e.g. USDC) */ - asset_address?: string; - /** Format: date */ - start_date?: string; - /** Format: date */ - end_date?: string; - /** @description Daily reward rate in USDC */ - rate_per_day?: number; - /** @description Cumulative rewards distributed */ - total_rewards?: number; - }[]; - /** @description Max spread to qualify for rewards */ - rewards_max_spread?: number | null; - /** @description Min order size to qualify for rewards */ - rewards_min_size?: number | null; - /** @description Native (non-sponsored) daily rate */ - native_daily_rate?: number | null; - /** @description Sponsored daily rate */ - sponsored_daily_rate?: number | null; - /** @description Combined daily rate (native + sponsored) */ - total_daily_rate?: number | null; - /** @description Number of sponsors */ - sponsors_count?: number | null; - } | null; - /** @description Unix timestamp in milliseconds */ - timestamp_ms?: number; - }; - /** @description Outer envelope for every webhook HTTP POST delivery. The `data` field contains the event-specific payload. Delivery headers sent with every POST: `X-Webhook-ID` (subscription UUID), `X-Delivery-ID` (this attempt's UUID), `X-Event-Type` (event name string, e.g. `trader_first_trade`), `X-Attempt` (attempt number, 1-indexed). When the webhook has a secret configured, `X-Webhook-Signature: sha256=` is also included — compute HMAC-SHA256 over the raw request body using your secret to verify. */ - WebhookDeliveryEnvelope: { - /** - * Format: uuid - * @description UUID of this specific delivery attempt (matches X-Delivery-ID header) - */ - id: string; - /** @description Event name (e.g. `trader_first_trade`). On test deliveries the suffix `_test` is appended. */ - event: string; - /** @description Event-specific payload — schema varies by event type; see the individual callback definitions */ - data: Record; - /** - * Format: int64 - * @description Unix timestamp in milliseconds when this delivery was created - */ - timestamp: number; - /** - * Format: uuid - * @description UUID of the webhook subscription that fired (matches X-Webhook-ID header) - */ - webhook_id: string; - /** @description Delivery attempt number. 1 = first attempt; increments on each retry. */ - attempt: number; - }; - /** @description Payload delivered when a tracked trader executes their first-ever trade on Polymarket */ - FirstTradePayload: { - /** @description Limit-order maker wallet address (lowercase) */ - trader: string; - /** @description Order filler wallet address (lowercase) */ - taker: string; - /** @description ERC-1155 outcome token ID */ - position_id: string; - /** @description Parent market condition ID (0x-prefixed hex) */ - condition_id?: string | null; - /** @description Outcome name (e.g. "Yes", "No") */ - outcome?: string | null; - /** @description Outcome index: 0 = Yes/Up, 1 = No */ - outcome_index?: number | null; - /** @description Market question text */ - question?: string | null; - /** @description Market slug */ - market_slug?: string | null; - /** @description Parent event slug */ - event_slug?: string | null; - /** @description Unique trade identifier */ - trade_id: string; - /** @description Transaction hash */ - hash: string; - /** - * Format: int64 - * @description Block number - */ - block: number; - /** - * Format: int64 - * @description Block confirmation timestamp (Unix seconds) - */ - confirmed_at: number; - /** @description USD size of the trade (6 decimal places) */ - amount_usd: number; - /** @description Outcome shares traded (6 decimal places) */ - shares_amount: number; - /** @description Fee paid in USD (6 decimal places) */ - fee: number; - /** - * @description Trade direction - * @enum {string} - */ - side: "Buy" | "Sell"; - /** @description Outcome token price (0.0–1.0) */ - price: number; - /** @description Exchange identifier */ - exchange: string; - /** @description Trade type identifier */ - trade_type: string; - }; - /** @description Payload delivered when a trader places their first trade in a specific market (fires once per trader+market pair) */ - NewMarketPayload: { - /** @description Limit-order maker wallet address (lowercase) */ - trader: string; - /** @description Order filler wallet address (lowercase) */ - taker: string; - /** @description ERC-1155 outcome token ID */ - position_id: string; - /** @description Parent market condition ID */ - condition_id?: string | null; - /** @description Outcome name (e.g. "Yes", "No") */ - outcome?: string | null; - /** @description Outcome index: 0 = Yes/Up, 1 = No */ - outcome_index?: number | null; - /** @description Market question text */ - question?: string | null; - /** @description Market slug */ - market_slug?: string | null; - /** @description Parent event slug */ - event_slug?: string | null; - /** @description Unique trade identifier */ - trade_id: string; - /** @description Transaction hash */ - hash: string; - /** - * Format: int64 - * @description Block number - */ - block: number; - /** - * Format: int64 - * @description Block confirmation timestamp (Unix seconds) - */ - confirmed_at: number; - /** @description USD size of the trade (6 decimal places) */ - amount_usd: number; - /** @description Outcome shares traded (6 decimal places) */ - shares_amount: number; - /** @description Fee paid in USD (6 decimal places) */ - fee: number; - /** - * @description Trade direction - * @enum {string} - */ - side: "Buy" | "Sell"; - /** @description Outcome token price (0.0–1.0) */ - price: number; - /** @description Implied probability (0.0–1.0); null when outcome is unknown */ - probability?: number | null; - /** @description Exchange identifier */ - exchange: string; - /** @description Trade type identifier */ - trade_type: string; - }; - /** @description Payload delivered when a trade exceeds the configured size and probability thresholds */ - WhaleTradePayload: { - /** @description Limit-order maker wallet address (lowercase) */ - trader: string; - /** @description Order filler wallet address (lowercase) */ - taker: string; - /** @description ERC-1155 outcome token ID */ - position_id: string; - /** @description Parent market condition ID */ - condition_id?: string | null; - /** @description Outcome name (e.g. "Yes", "No") */ - outcome?: string | null; - /** @description Outcome index: 0 = Yes/Up, 1 = No */ - outcome_index?: number | null; - /** @description Market question text */ - question?: string | null; - /** @description Market slug */ - market_slug?: string | null; - /** @description Parent event slug */ - event_slug?: string | null; - /** @description Unique trade identifier */ - trade_id: string; - /** @description Transaction hash */ - hash: string; - /** - * Format: int64 - * @description Block number - */ - block: number; - /** - * Format: int64 - * @description Block confirmation timestamp (Unix seconds) - */ - confirmed_at: number; - /** @description USD size of the trade (6 decimal places) */ - amount_usd: number; - /** @description Outcome shares traded (6 decimal places) */ - shares_amount: number; - /** @description Fee paid in USD (6 decimal places) */ - fee: number; - /** - * @description Trade direction - * @enum {string} - */ - side: "Buy" | "Sell"; - /** @description Outcome token price (0.0–1.0) */ - price: number; - /** @description Implied probability (0.0–1.0); null when outcome is unknown */ - probability?: number | null; - /** @description Exchange identifier */ - exchange: string; - /** @description Trade type identifier */ - trade_type: string; - }; - /** @description Payload delivered on every order-filled trade */ - NewTradePayload: { - /** @description Limit-order maker wallet address (lowercase) */ - trader: string; - /** @description Order filler wallet address (lowercase) */ - taker: string; - /** @description ERC-1155 outcome token ID */ - position_id: string; - /** @description Parent market condition ID */ - condition_id?: string | null; - /** @description Outcome name (e.g. "Yes", "No") */ - outcome?: string | null; - /** @description Outcome index: 0 = Yes/Up, 1 = No */ - outcome_index?: number | null; - /** @description Market question text */ - question?: string | null; - /** @description Market slug */ - market_slug?: string | null; - /** @description Parent event slug */ - event_slug?: string | null; - /** @description Unique trade identifier */ - trade_id: string; - /** @description Transaction hash */ - hash: string; - /** - * Format: int64 - * @description Block number - */ - block: number; - /** - * Format: int64 - * @description Block confirmation timestamp (Unix seconds) - */ - confirmed_at: number; - /** @description USD size of the trade (6 decimal places) */ - amount_usd: number; - /** @description Outcome shares traded (6 decimal places) */ - shares_amount: number; - /** @description Fee paid in USD (6 decimal places) */ - fee: number; - /** - * @description Trade direction - * @enum {string} - */ - side: "Buy" | "Sell"; - /** @description Outcome token price (0.0–1.0) */ - price: number; - /** @description Implied probability (0.0–1.0); null when outcome is unknown */ - probability?: number | null; - /** @description Exchange identifier */ - exchange: string; - /** @description Trade type identifier */ - trade_type: string; - }; - /** @description Payload delivered when a trader's global PnL (across all markets) crosses a configured threshold */ - GlobalPnlPayload: { - /** @description Trader wallet address (lowercase) */ - trader?: string | null; - /** - * @description PnL aggregation window - * @enum {string} - */ - timeframe: "1d" | "7d" | "30d" | "lifetime"; - /** @description Realized PnL in USD (positive = profit, negative = loss) */ - realized_pnl_usd?: number | null; - /** - * Format: int64 - * @description Number of distinct events traded - */ - events_traded?: number | null; - /** - * Format: int64 - * @description Number of distinct markets traded - */ - markets_traded?: number | null; - /** - * Format: int64 - * @description Total buy transactions - */ - total_buys?: number | null; - /** - * Format: int64 - * @description Total sell transactions - */ - total_sells?: number | null; - /** - * Format: int64 - * @description Total redemption transactions - */ - total_redemptions?: number | null; - /** - * Format: int64 - * @description Total merge transactions - */ - total_merges?: number | null; - /** @description Total USD volume (buys + sells + redemptions + merges) */ - total_volume_usd?: number | null; - /** @description Total buy volume in USD */ - buy_volume_usd?: number | null; - /** @description Total sell volume in USD */ - sell_volume_usd?: number | null; - /** @description Total redemption volume in USD */ - redemption_volume_usd?: number | null; - /** @description Total merge volume in USD */ - merge_volume_usd?: number | null; - /** - * Format: int64 - * @description Number of markets where trader realised a profit - */ - markets_won?: number | null; - /** - * Format: int64 - * @description Number of markets where trader realised a loss - */ - markets_lost?: number | null; - /** @description Market win rate as a percentage (0.0–100.0) */ - market_win_rate_pct?: number | null; - /** @description Average PnL per market in USD */ - avg_pnl_per_market?: number | null; - /** @description Average PnL per trade in USD */ - avg_pnl_per_trade?: number | null; - /** @description Average hold time across all positions (seconds) */ - avg_hold_time_seconds?: number | null; - /** @description Total fees paid in USD */ - total_fees?: number | null; - /** @description Best single-trade PnL in USD */ - best_trade_pnl_usd?: number | null; - /** @description Condition ID of the best trade */ - best_trade_condition_id?: string | null; - /** - * Format: int64 - * @description Timestamp of the first trade (Unix seconds) - */ - first_trade_at?: number | null; - /** - * Format: int64 - * @description Timestamp of the most recent trade (Unix seconds) - */ - last_trade_at?: number | null; - }; - /** @description Payload delivered when a trader's per-market PnL crosses a configured threshold */ - MarketPnlPayload: { - /** @description Trader wallet address (lowercase) */ - trader?: string | null; - /** @description Market condition ID */ - condition_id?: string | null; - /** @description Parent event slug */ - event_slug?: string | null; - /** - * @description PnL aggregation window - * @enum {string} - */ - timeframe: "1d" | "7d" | "30d" | "lifetime"; - /** - * Format: int64 - * @description Number of distinct outcomes traded in this market - */ - outcomes_traded?: number | null; - /** Format: int64 */ - total_buys?: number | null; - /** Format: int64 */ - total_sells?: number | null; - /** Format: int64 */ - total_redemptions?: number | null; - /** Format: int64 */ - total_merges?: number | null; - /** @description Total buy volume in USD */ - buy_usd?: number | null; - /** @description Total sell volume in USD */ - sell_usd?: number | null; - /** @description Total redemption volume in USD */ - redemption_usd?: number | null; - /** @description Total merge volume in USD */ - merge_usd?: number | null; - /** @description Realized PnL in USD for this market */ - realized_pnl_usd?: number | null; - /** - * Format: int64 - * @description Number of outcomes with positive PnL - */ - winning_outcomes?: number | null; - /** @description Total fees paid in USD for this market */ - total_fees?: number | null; - /** - * Format: int64 - * @description Timestamp of first trade in market (Unix seconds) - */ - first_trade_at?: number | null; - /** - * Format: int64 - * @description Timestamp of most recent trade in market (Unix seconds) - */ - last_trade_at?: number | null; - }; - /** @description Payload delivered when a trader's per-event PnL crosses a configured threshold */ - EventPnlPayload: { - /** @description Trader wallet address (lowercase) */ - trader?: string | null; - /** @description Event slug */ - event_slug?: string | null; - /** - * @description PnL aggregation window - * @enum {string} - */ - timeframe: "1d" | "7d" | "30d" | "lifetime"; - /** - * Format: int64 - * @description Number of distinct markets traded in this event - */ - markets_traded?: number | null; - /** Format: int64 */ - outcomes_traded?: number | null; - /** Format: int64 */ - total_buys?: number | null; - /** Format: int64 */ - total_sells?: number | null; - /** Format: int64 */ - total_redemptions?: number | null; - /** Format: int64 */ - total_merges?: number | null; - /** @description Total volume in USD */ - total_volume_usd?: number | null; - buy_usd?: number | null; - sell_usd?: number | null; - redemption_usd?: number | null; - merge_usd?: number | null; - /** @description Realized PnL in USD for this event */ - realized_pnl_usd?: number | null; - /** Format: int64 */ - winning_markets?: number | null; - /** Format: int64 */ - losing_markets?: number | null; - total_fees?: number | null; - /** - * Format: int64 - * @description Unix seconds - */ - first_trade_at?: number | null; - /** - * Format: int64 - * @description Unix seconds - */ - last_trade_at?: number | null; - }; - /** @description Payload delivered when a market's volume or transaction metrics cross a configured threshold */ - ConditionMetricsPayload: { - /** @description Market condition ID */ - condition_id?: string | null; - /** @description Aggregation window (e.g. "1h", "24h") */ - timeframe?: string | null; - /** @description Total trading volume in USD for this timeframe */ - volume_usd?: number | null; - /** @description Total fees collected in USD */ - fees?: number | null; - /** - * Format: int64 - * @description Total number of transactions - */ - txns?: number | null; - /** - * Format: int64 - * @description Number of unique traders - */ - unique_traders?: number | null; - }; - /** @description Payload delivered when an event's aggregated volume or transaction metrics cross a configured threshold */ - EventMetricsPayload: { - /** @description Event slug */ - event_slug?: string | null; - /** @description Aggregation window (e.g. "1h", "24h") */ - timeframe?: string | null; - /** @description Total aggregated volume across all markets in the event (USD) */ - volume_usd?: number | null; - /** @description Total fees collected in USD */ - fees?: number | null; - /** - * Format: int64 - * @description Total number of transactions - */ - txns?: number | null; - /** - * Format: int64 - * @description Number of unique traders - */ - unique_traders?: number | null; - }; - /** @description Payload delivered when a position's volume or transaction metrics cross a configured threshold */ - PositionMetricsPayload: { - /** @description ERC-1155 outcome token ID */ - position_id?: string | null; - /** @description Outcome name (e.g. "Yes", "No") */ - outcome?: string | null; - /** - * Format: int16 - * @description Outcome index - */ - outcome_index?: number | null; - /** @description Aggregation window (e.g. "1h", "24h") */ - timeframe?: string | null; - /** @description Total trading volume in USD */ - volume_usd?: number | null; - /** @description Buy volume in USD */ - buy_volume_usd?: number | null; - /** @description Sell volume in USD */ - sell_volume_usd?: number | null; - /** @description Total fees in USD */ - fees?: number | null; - /** Format: int64 */ - txns?: number | null; - /** Format: int64 */ - buys?: number | null; - /** Format: int64 */ - sells?: number | null; - /** Format: int64 */ - unique_traders?: number | null; - price_open?: number | null; - price_close?: number | null; - price_high?: number | null; - price_low?: number | null; - probability_open?: number | null; - probability_close?: number | null; - probability_high?: number | null; - probability_low?: number | null; - }; - /** @description Payload delivered when a market's trading volume crosses a USD milestone in the specified timeframe */ - VolumeMilestonePayload: { - /** @description Market condition ID */ - condition_id: string; - /** @description Aggregation window that crossed the milestone (e.g. "1h", "24h") */ - timeframe: string; - /** @description The USD milestone amount that was crossed */ - milestone_usd: number; - /** @description Current volume at time of trigger (USD) */ - current_volume_usd: number; - /** @description Total fees in USD for this timeframe */ - fees: number; - /** - * Format: int64 - * @description Total transactions in this timeframe - */ - txns: number; - }; - /** @description Payload delivered when an event's aggregated trading volume crosses a USD milestone */ - EventVolumeMilestonePayload: { - /** @description Event slug */ - event_slug: string; - /** @description Aggregation window (e.g. "1h", "24h") */ - timeframe: string; - /** @description The USD milestone amount that was crossed */ - milestone_usd: number; - /** @description Current aggregated event volume at time of trigger (USD) */ - current_volume_usd: number; - /** @description Total fees in USD for this timeframe */ - fees: number; - /** - * Format: int64 - * @description Total transactions in this timeframe - */ - txns: number; - }; - /** @description Payload delivered when a position's trading volume crosses a USD milestone */ - PositionVolumeMilestonePayload: { - /** @description Parent market condition ID */ - condition_id?: string | null; - /** @description ERC-1155 outcome token ID */ - position_id: string; - /** @description Outcome name (e.g. "Yes", "No") */ - outcome?: string | null; - /** - * Format: int16 - * @description Outcome index - */ - outcome_index?: number | null; - /** @description Aggregation window (e.g. "1h", "24h") */ - timeframe: string; - /** @description The USD milestone amount that was crossed */ - milestone_usd: number; - /** @description Current position volume at time of trigger (USD) */ - current_volume_usd: number; - /** @description Buy volume in USD for this timeframe */ - buy_volume_usd: number; - /** @description Sell volume in USD for this timeframe */ - sell_volume_usd: number; - /** @description Total fees in USD */ - fees: number; - /** Format: int64 */ - txns: number; - /** Format: int64 */ - buys: number; - /** Format: int64 */ - sells: number; - }; - ProbabilitySpikePayload: { - /** @description Outcome token ID */ - position_id: string; - /** @description Market condition ID */ - condition_id?: string | null; - /** @description Event slug */ - event_slug?: string | null; - /** @description Outcome name (e.g. "Yes", "No") */ - outcome?: string | null; - /** - * Format: int16 - * @description Outcome index - */ - outcome_index?: number | null; - /** @description Probability at the start of the observation window (baseline snapshot, 0.0–1.0) */ - previous_probability: number; - /** @description Current probability that triggered the spike (0.0–1.0) */ - current_probability: number; - /** - * @description `"up"` = probability rising, `"down"` = probability falling - * @enum {string} - */ - spike_direction: "up" | "down"; - /** @description Percentage move that triggered this notification. Positive = up, negative = down. */ - spike_pct: number; - }; - PriceSpikePayload: { - /** @description Outcome token ID */ - position_id: string; - /** @description Market condition ID */ - condition_id?: string | null; - /** @description Event slug */ - event_slug?: string | null; - /** @description Outcome name (e.g. "Yes", "No") */ - outcome?: string | null; - /** - * Format: int16 - * @description Outcome index - */ - outcome_index?: number | null; - /** @description Price at the start of the observation window (baseline snapshot, 0.0–1.0) */ - previous_price: number; - /** @description Current price that triggered the spike (0.0–1.0) */ - current_price: number; - /** - * @description `"up"` = price rising, `"down"` = price falling - * @enum {string} - */ - spike_direction: "up" | "down"; - /** @description Percentage move that triggered this notification. Positive = up, negative = down. */ - spike_pct: number; - }; - /** @description Payload delivered when a market's volume has spiked since the last snapshot */ - MarketVolumeSpikePayload: { - /** @description Market condition ID */ - condition_id: string; - /** @description Aggregation window (e.g. "1h", "24h") */ - timeframe: string; - /** @description Current volume at the time of the spike (USD) */ - current_volume_usd: number; - /** @description Volume at the snapshot baseline (USD) */ - snapshot_volume_usd: number; - /** @description New volume since the snapshot that triggered this notification (USD) */ - delta_volume_usd: number; - /** @description Volume growth as a percentage of the snapshot (e.g. 200.0 means volume tripled) */ - spike_pct: number; - /** - * Format: int64 - * @description Total transactions in this timeframe - */ - txns: number; - /** @description Total fees in USD for this timeframe */ - fees: number; - }; - /** @description Payload delivered when an event's aggregated volume has spiked since the last snapshot */ - EventVolumeSpikePayload: { - /** @description Event slug */ - event_slug: string; - /** @description Aggregation window (e.g. "1h", "24h") */ - timeframe: string; - /** @description Current aggregated event volume at time of the spike (USD) */ - current_volume_usd: number; - /** @description Volume at the snapshot baseline (USD) */ - snapshot_volume_usd: number; - /** @description New volume since the snapshot that triggered this notification (USD) */ - delta_volume_usd: number; - /** @description Volume growth as a percentage of the snapshot (e.g. 200.0 means volume tripled) */ - spike_pct: number; - /** Format: int64 */ - txns: number; - fees: number; - }; - /** @description Payload delivered when a position's volume has spiked since the last snapshot */ - PositionVolumeSpikePayload: { - /** @description ERC-1155 outcome token ID */ - position_id: string; - /** @description Parent market condition ID */ - condition_id: string; - /** @description Outcome name (e.g. "Yes", "No") */ - outcome?: string | null; - /** Format: int16 */ - outcome_index?: number | null; - /** @description Aggregation window (e.g. "1h", "24h") */ - timeframe: string; - /** @description Current position volume at the time of the spike (USD) */ - current_volume_usd: number; - /** @description Volume at the snapshot baseline (USD) */ - snapshot_volume_usd: number; - /** @description New volume since the snapshot that triggered this notification (USD) */ - delta_volume_usd: number; - /** @description Volume growth as a percentage of the snapshot (e.g. 200.0 means volume tripled) */ - spike_pct: number; - /** Format: int64 */ - txns: number; - fees: number; - }; - /** @description Payload delivered when a trade occurs at a near-certain-outcome price */ - CloseToBondPayload: { - /** @description Limit-order maker wallet address (lowercase) */ - trader: string; - /** @description Order filler wallet address (lowercase) */ - taker: string; - /** @description ERC-1155 outcome token ID */ - position_id: string; - /** @description Parent market condition ID */ - condition_id?: string | null; - /** @description Outcome name (e.g. "Yes", "No") */ - outcome?: string | null; - /** @description 0 = Yes/Up, 1 = No */ - outcome_index?: number | null; - question?: string | null; - market_slug?: string | null; - event_slug?: string | null; - trade_id: string; - /** @description Transaction hash */ - hash: string; - /** Format: int64 */ - block: number; - /** - * Format: int64 - * @description Unix seconds - */ - confirmed_at: number; - /** @description USD size of the trade */ - amount_usd: number; - shares_amount: number; - /** @description Fee paid in USD */ - fee: number; - /** @enum {string} */ - side: "Buy" | "Sell"; - /** @description Price that triggered the notification (0.0–1.0) */ - price: number; - /** @description Implied probability (0.0–1.0) */ - probability?: number | null; - /** - * @description "high" when near YES (price ≥ threshold), "low" when near NO (price ≤ threshold) - * @enum {string} - */ - bond_side: "high" | "low"; - /** @description The probability threshold from the subscription filter that was breached */ - threshold: number; - }; - /** @description An outcome entry within a newly created market */ - MarketCreatedOutcome: { - /** @description Outcome index (0 = Yes, 1 = No) */ - index: number; - /** @description Outcome name (e.g. "Yes", "No") */ - name: string; - /** @description ERC-1155 position token ID for this outcome */ - position_id: string; - }; - /** @description Payload delivered when a new prediction market is detected on-chain and enriched with Gamma API metadata */ - MarketCreatedPayload: { - /** @description Condition ID (0x-prefixed hex, lowercase) */ - condition_id: string; - /** @description Market slug */ - market_slug: string; - /** @description Parent event slug */ - event_slug?: string | null; - /** @description Parent event ID */ - event_id?: string | null; - /** @description Parent event title */ - event_title?: string | null; - /** @description Series slug (for recurring markets) */ - series_slug?: string | null; - /** @description List of market outcomes with their position IDs */ - outcomes: components["schemas"]["MarketCreatedOutcome"][]; - /** @description Full market question text */ - question: string; - /** @description Short display title */ - title?: string | null; - /** @description Market description */ - description: string; - /** @description Market category (e.g. "Sports", "Politics") */ - category?: string | null; - /** @description Market tags */ - tags: string[]; - /** @description Cover image URL */ - image_url?: string | null; - /** @description Whether this is a neg-risk market */ - neg_risk: boolean; - }; - /** @description Payload delivered on every raw Chainlink price tick for a tracked crypto asset */ - AssetPriceTickPayload: { - /** - * @description Asset symbol - * @enum {string} - */ - symbol: "BTC" | "ETH" | "SOL" | "XRP" | "DOGE" | "BNB" | "HYPE"; - /** @description Current asset price in USD from the Chainlink feed */ - price: number; - /** - * Format: int64 - * @description Tick timestamp (milliseconds since Unix epoch) - */ - timestamp_ms: number; - }; - /** @description Payload delivered twice per candle — once on open and once on close. `close_price` is 0.0 on the "open" update. */ - AssetPriceWindowUpdatePayload: { - /** - * @description Asset symbol - * @enum {string} - */ - symbol: "BTC" | "ETH" | "SOL" | "XRP" | "DOGE" | "BNB" | "HYPE"; - /** - * @description Candle / window size - * @enum {string} - */ - variant: "5m" | "15m" | "1h" | "4h" | "1d" | "24h"; - /** - * Format: int64 - * @description Window start timestamp (milliseconds since Unix epoch) - */ - start_time: number; - /** - * Format: int64 - * @description Window end timestamp (milliseconds since Unix epoch) - */ - end_time: number; - /** @description Opening price at start_time (USD) */ - open_price: number; - /** @description Closing price at end_time (USD). 0.0 when update_type is "open" (not yet available). */ - close_price: number; - /** - * @description "open" when the candle opens, "close" when it closes with a confirmed price - * @enum {string} - */ - update_type: "open" | "close"; - }; - /** @description Subscription filters for the `trader_first_trade` event. All fields are optional. */ - TraderFirstTradeFilters: { - /** @description Only fire for trades by these wallet addresses (lowercase). Empty = all traders. */ - wallet_addresses?: string[]; - /** @description Restrict to trades in these markets. Empty = all markets. */ - condition_ids?: string[]; - /** @description Restrict to trades in markets belonging to these events. */ - event_slugs?: string[]; - /** @description Minimum trade size in USD. Omit to match all sizes. */ - min_usd_value?: number; - /** @description Only fire when the outcome probability is ≥ this value. */ - min_probability?: number; - /** @description Only fire when the outcome probability is ≤ this value. */ - max_probability?: number; - /** @description When `true`, suppress webhooks for short-term "updown" markets (event slugs containing `updown`). Default: `false`. */ - exclude_shortterm_markets?: boolean; - }; - /** @description Subscription filters for the `trader_new_market` event. All fields are optional. */ - TraderNewMarketFilters: { - /** @description Only fire for these wallet addresses (lowercase). Empty = all traders. */ - wallet_addresses?: string[]; - /** @description Restrict to these markets. */ - condition_ids?: string[]; - /** @description Restrict to markets belonging to these events. */ - event_slugs?: string[]; - /** @description When `true`, suppress webhooks for short-term "updown" markets. Default: `false`. */ - exclude_shortterm_markets?: boolean; - }; - /** @description Subscription filters for the `trader_whale_trade` event. All fields are optional. */ - TraderWhaleTradeFilters: { - /** @description Only fire for trades by these wallet addresses. Empty = all traders. */ - wallet_addresses?: string[]; - /** @description Restrict to these markets. */ - condition_ids?: string[]; - /** @description Restrict to markets belonging to these events. */ - event_slugs?: string[]; - /** @description Minimum trade size in USD. Defaults to 0 (matches all trades). */ - min_usd_value?: number; - /** @description Only fire when outcome probability is ≥ this value. */ - min_probability?: number; - /** @description Only fire when outcome probability is ≤ this value. */ - max_probability?: number; - /** @description When `true`, suppress webhooks for short-term "updown" markets. Default: `false`. */ - exclude_shortterm_markets?: boolean; - }; - /** @description Subscription filters for the `trader_new_trade` event. All fields are optional. */ - TraderNewTradeFilters: { - /** @description Only fire for trades by these wallet addresses. Empty = all traders. */ - wallet_addresses?: string[]; - /** @description Restrict to these markets. */ - condition_ids?: string[]; - /** @description Restrict to markets belonging to these events. */ - event_slugs?: string[]; - /** @description Minimum trade size in USD. Defaults to 0 (matches all trades). */ - min_usd_value?: number; - /** @description Only fire when outcome probability is ≥ this value. */ - min_probability?: number; - /** @description Only fire when outcome probability is ≤ this value. */ - max_probability?: number; - /** @description When `true`, suppress webhooks for short-term "updown" markets. Default: `false`. */ - exclude_shortterm_markets?: boolean; - }; - /** @description Subscription filters for the `trader_global_pnl` event. All fields are optional. */ - TraderGlobalPnlFilters: { - /** @description Track only these trader wallet addresses. Empty = all traders. */ - traders?: string[]; - /** @description Only fire when realized PnL ≥ this value (USD). Use negative values for loss thresholds. */ - min_realized_pnl_usd?: number; - /** @description Only fire when realized PnL ≤ this value (USD). */ - max_realized_pnl_usd?: number; - /** @description Only fire when total trading volume ≥ this value (USD). */ - min_volume_usd?: number; - /** @description Only fire when total trading volume ≤ this value (USD). */ - max_volume_usd?: number; - /** @description Only fire when buy volume ≥ this value (USD). */ - min_buy_usd?: number; - /** @description Only fire when sell volume ≥ this value (USD). */ - min_sell_volume_usd?: number; - /** @description Only fire when market win rate ≥ this percentage (0.0–100.0). */ - min_win_rate?: number; - /** - * Format: int64 - * @description Only fire when the trader has traded in ≥ this many markets. - */ - min_markets_traded?: number; - /** @description Restrict to these PnL windows. Empty = all windows. */ - timeframes?: ("1d" | "7d" | "30d" | "lifetime")[]; - }; - /** @description Subscription filters for the `trader_market_pnl` event. All fields are optional. */ - TraderMarketPnlFilters: { - /** @description Track only these trader wallet addresses. */ - traders?: string[]; - /** @description Restrict to these markets. */ - condition_ids?: string[]; - /** @description Restrict to markets in these events. */ - event_slugs?: string[]; - /** @description Only fire when per-market realized PnL ≥ this value (USD). */ - min_realized_pnl_usd?: number; - /** @description Only fire when per-market realized PnL ≤ this value (USD). */ - max_realized_pnl_usd?: number; - /** @description Only fire when total volume (buy + sell + redemption + merge) ≥ this value (USD). */ - min_volume_usd?: number; - /** @description Only fire when total volume ≤ this value (USD). */ - max_volume_usd?: number; - /** @description Only fire when buy volume in the market ≥ this value (USD). */ - min_buy_usd?: number; - /** @description Only fire when sell volume in the market ≥ this value (USD). */ - min_sell_volume_usd?: number; - /** @description Restrict to these PnL windows. */ - timeframes?: ("1d" | "7d" | "30d" | "lifetime")[]; - /** @description When `true`, suppress webhooks for short-term "updown" markets. Default: `false`. */ - exclude_shortterm_markets?: boolean; - }; - /** @description Subscription filters for the `trader_event_pnl` event. All fields are optional. */ - TraderEventPnlFilters: { - /** @description Track only these trader wallet addresses. */ - traders?: string[]; - /** @description Restrict to these events. */ - event_slugs?: string[]; - /** @description Only fire when per-event realized PnL ≥ this value (USD). */ - min_realized_pnl_usd?: number; - /** @description Only fire when per-event realized PnL ≤ this value (USD). */ - max_realized_pnl_usd?: number; - /** @description Only fire when total event volume ≥ this value (USD). */ - min_volume_usd?: number; - /** @description Only fire when total event volume ≤ this value (USD). */ - max_volume_usd?: number; - /** @description Only fire when buy volume within the event ≥ this value (USD). */ - min_buy_usd?: number; - /** @description Only fire when sell volume within the event ≥ this value (USD). */ - min_sell_volume_usd?: number; - /** - * Format: int64 - * @description Only fire when the trader has traded in ≥ this many markets within the event. - */ - min_markets_traded?: number; - /** @description Restrict to these PnL windows. */ - timeframes?: ("1d" | "7d" | "30d" | "lifetime")[]; - /** @description When `true`, suppress webhooks for short-term "updown" markets. Default: `false`. */ - exclude_shortterm_markets?: boolean; - }; - /** @description Subscription filters for the `condition_metrics` event. All fields are optional. */ - MarketMetricsFilters: { - /** @description Restrict to these markets. Empty = all markets. */ - condition_ids?: string[]; - /** @description Restrict to markets in these events. */ - event_slugs?: string[]; - /** @description Restrict to these aggregation windows. Empty = all windows. */ - timeframes?: ("1m" | "5m" | "30m" | "1h" | "6h" | "24h" | "7d" | "30d")[]; - /** @description Only fire when volume ≥ this value (USD). */ - min_volume_usd?: number; - /** @description Only fire when volume ≤ this value (USD). */ - max_volume_usd?: number; - /** - * Format: int64 - * @description Only fire when transaction count ≥ this value. - */ - min_txns?: number; - /** - * Format: int64 - * @description Only fire when unique trader count ≥ this value. - */ - min_unique_traders?: number; - /** @description Only fire when total fees ≥ this value (USD). */ - min_fees?: number; - }; - /** @description Subscription filters for the `event_metrics` event. All fields are optional. */ - EventMetricsFilters: { - /** @description Restrict to these events. Empty = all events. */ - event_slugs?: string[]; - /** @description Restrict to these aggregation windows. */ - timeframes?: ("1m" | "5m" | "30m" | "1h" | "6h" | "24h" | "7d" | "30d")[]; - /** @description Only fire when aggregated event volume ≥ this value (USD). */ - min_volume_usd?: number; - max_volume_usd?: number; - /** Format: int64 */ - min_txns?: number; - /** Format: int64 */ - min_unique_traders?: number; - min_fees?: number; - /** @description When `true`, suppress webhooks for short-term "updown" markets. Default: `false`. */ - exclude_shortterm_markets?: boolean; - }; - /** @description Subscription filters for the `position_metrics` event. All fields are optional. */ - PositionMetricsFilters: { - /** @description Restrict to these outcome token IDs. */ - position_ids?: string[]; - /** @description Restrict to positions within these markets. */ - condition_ids?: string[]; - /** @description Restrict to positions with these outcome names (e.g. ["Yes", "No"]). */ - outcomes?: string[]; - /** @description Restrict to these aggregation windows. */ - timeframes?: ("1m" | "5m" | "30m" | "1h" | "6h" | "24h" | "7d" | "30d")[]; - /** @description Only fire when position volume ≥ this value (USD). */ - min_volume_usd?: number; - max_volume_usd?: number; - min_buy_usd?: number; - min_sell_volume_usd?: number; - /** Format: int64 */ - min_txns?: number; - /** Format: int64 */ - min_unique_traders?: number; - /** @description Only fire when price change % ≥ this value. */ - min_price_change_pct?: number; - /** @description Only fire when probability change % ≥ this value. */ - min_probability_change_pct?: number; - min_fees?: number; - }; - /** @description Subscription filters for the `market_volume_milestone` event. */ - MarketVolumeMilestoneFilters: { - /** @description **Required.** Aggregation windows to monitor (e.g. ["1h", "24h"]). */ - timeframes: ("1m" | "5m" | "30m" | "1h" | "6h" | "24h" | "7d" | "30d")[]; - /** @description Restrict to these markets. Empty = all markets. */ - condition_ids?: string[]; - /** @description Specific USD milestones to trigger on (e.g. [10000, 100000, 1000000]). Empty = all milestones. */ - milestone_amounts?: number[]; - }; - /** @description Subscription filters for the `event_volume_milestone` event. */ - EventVolumeMilestoneFilters: { - /** @description **Required.** Aggregation windows to monitor. */ - timeframes: ("1m" | "5m" | "30m" | "1h" | "6h" | "24h" | "7d" | "30d")[]; - /** @description Restrict to these events. */ - event_slugs?: string[]; - /** @description Specific USD milestones to trigger on. */ - milestone_amounts?: number[]; - /** @description When `true`, suppress webhooks for short-term "updown" markets. Default: `false`. */ - exclude_shortterm_markets?: boolean; - }; - /** @description Subscription filters for the `position_volume_milestone` event. */ - PositionVolumeMilestoneFilters: { - /** @description **Required.** Aggregation windows to monitor. */ - timeframes: ("1m" | "5m" | "30m" | "1h" | "6h" | "24h" | "7d" | "30d")[]; - /** @description Restrict to these outcome token IDs. */ - position_ids?: string[]; - /** @description Restrict to positions within these markets. */ - condition_ids?: string[]; - /** @description Specific USD milestones to trigger on. */ - milestone_amounts?: number[]; - }; - /** @description Subscription filters for the `probability_spike` event. */ - ProbabilitySpikeFilters: { - /** @description Restrict to specific outcome token IDs. Empty = all positions. */ - position_ids?: string[]; - /** @description Restrict to specific market condition IDs. Empty = all markets. */ - condition_ids?: string[]; - /** @description Restrict to specific events. Empty = all events. */ - event_slugs?: string[]; - /** @description Restrict to these outcome names (e.g. ["Yes", "No"]). */ - outcomes?: string[]; - /** @description Minimum probability percentage move to trigger (e.g. `10` for a 10% move). */ - min_probability_change_pct?: number; - /** - * @description `"up"` = probability rising only (default when omitted), `"down"` = falling only, `"both"` = either direction. - * @enum {string} - */ - spike_direction?: "up" | "down" | "both"; - /** @description Observation window in seconds. The first trade in each window sets the reference price; subsequent trades are compared to it. E.g. `60` detects moves that occur within 60 seconds. */ - window_secs?: number; - /** @description When `true`, suppress webhooks for short-term "updown" markets. Default: `false`. */ - exclude_shortterm_markets?: boolean; - }; - /** @description Subscription filters for the `price_spike` event. */ - PriceSpikeFilters: { - /** @description Restrict to specific outcome token IDs. Empty = all positions. */ - position_ids?: string[]; - /** @description Restrict to specific market condition IDs. Empty = all markets. */ - condition_ids?: string[]; - /** @description Restrict to specific events. Empty = all events. */ - event_slugs?: string[]; - /** @description Restrict to these outcome names (e.g. ["Yes", "No"]). */ - outcomes?: string[]; - /** @description Minimum price percentage move to trigger (e.g. `10` for a 10% move). */ - min_price_change_pct?: number; - /** - * @description `"up"` = price rising only (default when omitted), `"down"` = falling only, `"both"` = either direction. - * @enum {string} - */ - spike_direction?: "up" | "down" | "both"; - /** @description Observation window in seconds. The first trade in each window sets the reference price; subsequent trades are compared to it. E.g. `60` detects moves that occur within 60 seconds. */ - window_secs?: number; - /** @description When `true`, suppress webhooks for short-term "updown" markets. Default: `false`. */ - exclude_shortterm_markets?: boolean; - }; - /** @description Subscription filters for the `market_volume_spike` event. `spike_ratio` is required. */ - MarketVolumeSpikeFilters: { - /** @description **Required.** Multiplier threshold (must be > 1.0). Fires when current volume >= snapshot × ratio. The snapshot is set automatically on first data and resets after each fire. */ - spike_ratio: number; - /** @description Force snapshot reset after this many seconds (max 600 / 10 minutes). */ - window_secs?: number; - /** @description Restrict to these markets. Empty = all markets. */ - condition_ids?: string[]; - /** @description Restrict to these aggregation windows. Empty = all windows. */ - timeframes?: ("1m" | "5m" | "30m" | "1h" | "6h" | "1d" | "24h" | "7d" | "30d")[]; - }; - /** @description Subscription filters for the `event_volume_spike` event. `spike_ratio` is required. */ - EventVolumeSpikeFilters: { - /** @description **Required.** Multiplier threshold (must be > 1.0). Fires when current volume >= snapshot × ratio. */ - spike_ratio: number; - /** @description Force snapshot reset after this many seconds (max 600 / 10 minutes). */ - window_secs?: number; - /** @description Restrict to these events. */ - event_slugs?: string[]; - /** @description Restrict to these aggregation windows. */ - timeframes?: ("1m" | "5m" | "30m" | "1h" | "6h" | "1d" | "24h" | "7d" | "30d")[]; - /** @description When `true`, suppress webhooks for short-term "updown" markets. Default: `false`. */ - exclude_shortterm_markets?: boolean; - }; - /** - * @description All alert event types supported by both HTTP webhooks and the alerts WebSocket. - * @enum {string} - */ - WsAlertEventType: "trader_first_trade" | "trader_new_market" | "trader_whale_trade" | "trader_new_trade" | "trader_global_pnl" | "trader_market_pnl" | "trader_event_pnl" | "condition_metrics" | "event_metrics" | "position_metrics" | "market_volume_milestone" | "event_volume_milestone" | "position_volume_milestone" | "probability_spike" | "price_spike" | "market_volume_spike" | "event_volume_spike" | "position_volume_spike" | "close_to_bond" | "market_created" | "asset_price_tick" | "asset_price_window_update"; - /** @description Server acknowledgement for a successful alert subscription. */ - WsAlertSubscribedResponse: { - /** @enum {string} */ - op: "subscribed"; - event: components["schemas"]["WsAlertEventType"]; - /** Format: uuid */ - subscription_id: string; - }; - /** @description Server acknowledgement for a successful alert unsubscription. */ - WsAlertUnsubscribedResponse: { - /** @enum {string} */ - op: "unsubscribed"; - event: components["schemas"]["WsAlertEventType"]; - }; - /** @description Error returned by the alerts WebSocket when a message is invalid or a subscription request fails. */ - WsAlertErrorResponse: { - error: string; - }; - WsAlertTraderFirstTradeSubscribeMessage: { - /** @enum {string} */ - op: "subscribe"; - /** @enum {string} */ - event: "trader_first_trade"; - } & components["schemas"]["TraderFirstTradeFilters"] & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "trader_first_trade"; - }; - WsAlertTraderFirstTradeUnsubscribeMessage: { - /** @enum {string} */ - op: "unsubscribe"; - /** @enum {string} */ - event: "trader_first_trade"; - } & components["schemas"]["TraderFirstTradeFilters"] & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "trader_first_trade"; - }; - /** - * @description Pushed `trader_first_trade` alert. The `data` payload matches the corresponding HTTP webhook payload schema. - * @example { - * "event": "trader_first_trade", - * "timestamp": 1743500000000, - * "data": { - * "trader": "0x0000000000000000000000000000000000000000", - * "taker": "0x0000000000000000000000000000000000000000", - * "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", - * "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", - * "outcome": "Yes", - * "outcome_index": 0, - * "question": "Will this test webhook fire correctly?", - * "market_slug": "test-market-0000000000", - * "event_slug": "test-event-0000000000", - * "trade_id": "00000000-0000-0000-0000-000000000000", - * "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", - * "block": 0, - * "confirmed_at": 1700000000, - * "amount_usd": 125, - * "shares_amount": 250, - * "fee": 0.125, - * "side": "Buy", - * "price": 0.5, - * "exchange": "polymarket", - * "trade_type": "OrderFilled" - * } - * } - */ - WsAlertTraderFirstTradeEvent: { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "trader_first_trade"; - /** - * Format: int64 - * @description Unix timestamp in milliseconds - */ - timestamp: number; - data: components["schemas"]["FirstTradePayload"]; - }; - WsAlertTraderNewMarketSubscribeMessage: { - /** @enum {string} */ - op: "subscribe"; - /** @enum {string} */ - event: "trader_new_market"; - } & components["schemas"]["TraderNewMarketFilters"] & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "trader_new_market"; - }; - WsAlertTraderNewMarketUnsubscribeMessage: { - /** @enum {string} */ - op: "unsubscribe"; - /** @enum {string} */ - event: "trader_new_market"; - } & components["schemas"]["TraderNewMarketFilters"] & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "trader_new_market"; - }; - /** - * @description Pushed `trader_new_market` alert. The `data` payload matches the corresponding HTTP webhook payload schema. - * @example { - * "event": "trader_new_market", - * "timestamp": 1743500000000, - * "data": { - * "trader": "0x0000000000000000000000000000000000000000", - * "taker": "0x0000000000000000000000000000000000000000", - * "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", - * "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", - * "outcome": "Yes", - * "outcome_index": 0, - * "question": "Will this test webhook fire correctly?", - * "market_slug": "test-market-0000000000", - * "event_slug": "test-event-0000000000", - * "trade_id": "00000000-0000-0000-0000-000000000000", - * "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", - * "block": 0, - * "confirmed_at": 1700000000, - * "amount_usd": 125, - * "shares_amount": 250, - * "fee": 0.125, - * "side": "Buy", - * "price": 0.5, - * "probability": 0.5, - * "exchange": "polymarket", - * "trade_type": "OrderFilled" - * } - * } - */ - WsAlertTraderNewMarketEvent: { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "trader_new_market"; - /** - * Format: int64 - * @description Unix timestamp in milliseconds - */ - timestamp: number; - data: components["schemas"]["NewMarketPayload"]; - }; - WsAlertTraderWhaleTradeSubscribeMessage: { - /** @enum {string} */ - op: "subscribe"; - /** @enum {string} */ - event: "trader_whale_trade"; - } & components["schemas"]["TraderWhaleTradeFilters"] & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "trader_whale_trade"; - }; - WsAlertTraderWhaleTradeUnsubscribeMessage: { - /** @enum {string} */ - op: "unsubscribe"; - /** @enum {string} */ - event: "trader_whale_trade"; - } & components["schemas"]["TraderWhaleTradeFilters"] & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "trader_whale_trade"; - }; - /** - * @description Pushed `trader_whale_trade` alert. The `data` payload matches the corresponding HTTP webhook payload schema. - * @example { - * "event": "trader_whale_trade", - * "timestamp": 1743500000000, - * "data": { - * "trader": "0x0000000000000000000000000000000000000000", - * "taker": "0x0000000000000000000000000000000000000000", - * "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", - * "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", - * "outcome": "Yes", - * "outcome_index": 0, - * "question": "Will this test webhook fire correctly?", - * "market_slug": "test-market-0000000000", - * "event_slug": "test-event-0000000000", - * "trade_id": "00000000-0000-0000-0000-000000000000", - * "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", - * "block": 0, - * "confirmed_at": 1700000000, - * "amount_usd": 125, - * "shares_amount": 250, - * "fee": 0.125, - * "side": "Buy", - * "price": 0.5, - * "probability": 0.5, - * "exchange": "polymarket", - * "trade_type": "OrderFilled" - * } - * } - */ - WsAlertTraderWhaleTradeEvent: { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "trader_whale_trade"; - /** - * Format: int64 - * @description Unix timestamp in milliseconds - */ - timestamp: number; - data: components["schemas"]["WhaleTradePayload"]; - }; - WsAlertTraderNewTradeSubscribeMessage: { - /** @enum {string} */ - op: "subscribe"; - /** @enum {string} */ - event: "trader_new_trade"; - } & components["schemas"]["TraderNewTradeFilters"] & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "trader_new_trade"; - }; - WsAlertTraderNewTradeUnsubscribeMessage: { - /** @enum {string} */ - op: "unsubscribe"; - /** @enum {string} */ - event: "trader_new_trade"; - } & components["schemas"]["TraderNewTradeFilters"] & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "trader_new_trade"; - }; - /** - * @description Pushed `trader_new_trade` alert. The `data` payload matches the corresponding HTTP webhook payload schema. - * @example { - * "event": "trader_new_trade", - * "timestamp": 1743500000000, - * "data": { - * "trader": "0x0000000000000000000000000000000000000000", - * "taker": "0x0000000000000000000000000000000000000000", - * "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", - * "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", - * "outcome": "Yes", - * "outcome_index": 0, - * "question": "Will this test webhook fire correctly?", - * "market_slug": "test-market-0000000000", - * "event_slug": "test-event-0000000000", - * "trade_id": "00000000-0000-0000-0000-000000000000", - * "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", - * "block": 0, - * "confirmed_at": 1700000000, - * "amount_usd": 25, - * "shares_amount": 50, - * "fee": 0.025, - * "side": "Buy", - * "price": 0.5, - * "probability": 0.5, - * "exchange": "polymarket", - * "trade_type": "OrderFilled" - * } - * } - */ - WsAlertTraderNewTradeEvent: { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "trader_new_trade"; - /** - * Format: int64 - * @description Unix timestamp in milliseconds - */ - timestamp: number; - data: components["schemas"]["NewTradePayload"]; - }; - WsAlertTraderGlobalPnlSubscribeMessage: { - /** @enum {string} */ - op: "subscribe"; - /** @enum {string} */ - event: "trader_global_pnl"; - } & components["schemas"]["TraderGlobalPnlFilters"] & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "trader_global_pnl"; - }; - WsAlertTraderGlobalPnlUnsubscribeMessage: { - /** @enum {string} */ - op: "unsubscribe"; - /** @enum {string} */ - event: "trader_global_pnl"; - } & components["schemas"]["TraderGlobalPnlFilters"] & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "trader_global_pnl"; - }; - /** - * @description Pushed `trader_global_pnl` alert. The `data` payload matches the corresponding HTTP webhook payload schema. - * @example { - * "event": "trader_global_pnl", - * "timestamp": 1743500000000, - * "data": { - * "trader": "0x0000000000000000000000000000000000000000", - * "timeframe": "7d", - * "realized_pnl_usd": 250, - * "events_traded": 3, - * "markets_traded": 5, - * "total_buys": 12, - * "total_sells": 8, - * "total_redemptions": 1, - * "total_merges": 0, - * "total_volume_usd": 1500, - * "buy_volume_usd": 900, - * "sell_volume_usd": 600, - * "redemption_volume_usd": 50, - * "merge_volume_usd": 0, - * "markets_won": 3, - * "markets_lost": 2, - * "market_win_rate_pct": 60, - * "avg_pnl_per_market": 50, - * "avg_pnl_per_trade": 12.5, - * "avg_hold_time_seconds": 86400, - * "total_fees": 7.5, - * "best_trade_pnl_usd": 180, - * "best_trade_condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", - * "first_trade_at": 1700000000, - * "last_trade_at": 1700000000 - * } - * } - */ - WsAlertTraderGlobalPnlEvent: { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "trader_global_pnl"; - /** - * Format: int64 - * @description Unix timestamp in milliseconds - */ - timestamp: number; - data: components["schemas"]["GlobalPnlPayload"]; - }; - WsAlertTraderMarketPnlSubscribeMessage: { - /** @enum {string} */ - op: "subscribe"; - /** @enum {string} */ - event: "trader_market_pnl"; - } & components["schemas"]["TraderMarketPnlFilters"] & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "trader_market_pnl"; - }; - WsAlertTraderMarketPnlUnsubscribeMessage: { - /** @enum {string} */ - op: "unsubscribe"; - /** @enum {string} */ - event: "trader_market_pnl"; - } & components["schemas"]["TraderMarketPnlFilters"] & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "trader_market_pnl"; - }; - /** - * @description Pushed `trader_market_pnl` alert. The `data` payload matches the corresponding HTTP webhook payload schema. - * @example { - * "event": "trader_market_pnl", - * "timestamp": 1743500000000, - * "data": { - * "trader": "0x0000000000000000000000000000000000000000", - * "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", - * "event_slug": "test-event-0000000000", - * "timeframe": "7d", - * "outcomes_traded": 2, - * "total_buys": 4, - * "total_sells": 3, - * "total_redemptions": 1, - * "total_merges": 0, - * "buy_usd": 300, - * "sell_usd": 200, - * "redemption_usd": 50, - * "merge_usd": 0, - * "realized_pnl_usd": 100, - * "winning_outcomes": 1, - * "total_fees": 2.5, - * "first_trade_at": 1700000000, - * "last_trade_at": 1700000000 - * } - * } - */ - WsAlertTraderMarketPnlEvent: { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "trader_market_pnl"; - /** - * Format: int64 - * @description Unix timestamp in milliseconds - */ - timestamp: number; - data: components["schemas"]["MarketPnlPayload"]; - }; - WsAlertTraderEventPnlSubscribeMessage: { - /** @enum {string} */ - op: "subscribe"; - /** @enum {string} */ - event: "trader_event_pnl"; - } & components["schemas"]["TraderEventPnlFilters"] & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "trader_event_pnl"; - }; - WsAlertTraderEventPnlUnsubscribeMessage: { - /** @enum {string} */ - op: "unsubscribe"; - /** @enum {string} */ - event: "trader_event_pnl"; - } & components["schemas"]["TraderEventPnlFilters"] & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "trader_event_pnl"; - }; - /** - * @description Pushed `trader_event_pnl` alert. The `data` payload matches the corresponding HTTP webhook payload schema. - * @example { - * "event": "trader_event_pnl", - * "timestamp": 1743500000000, - * "data": { - * "trader": "0x0000000000000000000000000000000000000000", - * "event_slug": "test-event-0000000000", - * "timeframe": "7d", - * "markets_traded": 2, - * "outcomes_traded": 3, - * "total_buys": 6, - * "total_sells": 4, - * "total_redemptions": 1, - * "total_merges": 0, - * "total_volume_usd": 800, - * "buy_usd": 480, - * "sell_usd": 320, - * "redemption_usd": 50, - * "merge_usd": 0, - * "realized_pnl_usd": 150, - * "winning_markets": 1, - * "losing_markets": 1, - * "total_fees": 4, - * "first_trade_at": 1700000000, - * "last_trade_at": 1700000000 - * } - * } - */ - WsAlertTraderEventPnlEvent: { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "trader_event_pnl"; - /** - * Format: int64 - * @description Unix timestamp in milliseconds - */ - timestamp: number; - data: components["schemas"]["EventPnlPayload"]; - }; - WsAlertConditionMetricsSubscribeMessage: { - /** @enum {string} */ - op: "subscribe"; - /** @enum {string} */ - event: "condition_metrics"; - } & components["schemas"]["MarketMetricsFilters"] & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "condition_metrics"; - }; - WsAlertConditionMetricsUnsubscribeMessage: { - /** @enum {string} */ - op: "unsubscribe"; - /** @enum {string} */ - event: "condition_metrics"; - } & components["schemas"]["MarketMetricsFilters"] & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "condition_metrics"; - }; - /** - * @description Pushed `condition_metrics` alert. The `data` payload matches the corresponding HTTP webhook payload schema. - * @example { - * "event": "condition_metrics", - * "timestamp": 1743500000000, - * "data": { - * "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", - * "timeframe": "1h", - * "volume_usd": 50000, - * "fees": 250, - * "txns": 320, - * "unique_traders": 85 - * } - * } - */ - WsAlertConditionMetricsEvent: { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "condition_metrics"; - /** - * Format: int64 - * @description Unix timestamp in milliseconds - */ - timestamp: number; - data: components["schemas"]["ConditionMetricsPayload"]; - }; - WsAlertEventMetricsSubscribeMessage: { - /** @enum {string} */ - op: "subscribe"; - /** @enum {string} */ - event: "event_metrics"; - } & components["schemas"]["EventMetricsFilters"] & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "event_metrics"; - }; - WsAlertEventMetricsUnsubscribeMessage: { - /** @enum {string} */ - op: "unsubscribe"; - /** @enum {string} */ - event: "event_metrics"; - } & components["schemas"]["EventMetricsFilters"] & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "event_metrics"; - }; - /** - * @description Pushed `event_metrics` alert. The `data` payload matches the corresponding HTTP webhook payload schema. - * @example { - * "event": "event_metrics", - * "timestamp": 1743500000000, - * "data": { - * "event_slug": "test-event-0000000000", - * "timeframe": "1h", - * "volume_usd": 120000, - * "fees": 600, - * "txns": 740, - * "unique_traders": 210 - * } - * } - */ - WsAlertEventMetricsEvent: { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "event_metrics"; - /** - * Format: int64 - * @description Unix timestamp in milliseconds - */ - timestamp: number; - data: components["schemas"]["EventMetricsPayload"]; - }; - WsAlertPositionMetricsSubscribeMessage: { - /** @enum {string} */ - op: "subscribe"; - /** @enum {string} */ - event: "position_metrics"; - } & components["schemas"]["PositionMetricsFilters"] & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "position_metrics"; - }; - WsAlertPositionMetricsUnsubscribeMessage: { - /** @enum {string} */ - op: "unsubscribe"; - /** @enum {string} */ - event: "position_metrics"; - } & components["schemas"]["PositionMetricsFilters"] & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "position_metrics"; - }; - /** - * @description Pushed `position_metrics` alert. The `data` payload matches the corresponding HTTP webhook payload schema. - * @example { - * "event": "position_metrics", - * "timestamp": 1743500000000, - * "data": { - * "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", - * "outcome": "Yes", - * "outcome_index": 0, - * "timeframe": "1h", - * "volume_usd": 25000, - * "buy_volume_usd": 15000, - * "sell_volume_usd": 10000, - * "fees": 125, - * "txns": 160, - * "buys": 95, - * "sells": 65, - * "unique_traders": 48, - * "price_open": 0.48, - * "price_close": 0.52, - * "price_high": 0.55, - * "price_low": 0.46, - * "probability_open": 0.48, - * "probability_close": 0.52, - * "probability_high": 0.55, - * "probability_low": 0.46 - * } - * } - */ - WsAlertPositionMetricsEvent: { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "position_metrics"; - /** - * Format: int64 - * @description Unix timestamp in milliseconds - */ - timestamp: number; - data: components["schemas"]["PositionMetricsPayload"]; - }; - WsAlertMarketVolumeMilestoneSubscribeMessage: { - /** @enum {string} */ - op: "subscribe"; - /** @enum {string} */ - event: "market_volume_milestone"; - } & components["schemas"]["MarketVolumeMilestoneFilters"] & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "market_volume_milestone"; - }; - WsAlertMarketVolumeMilestoneUnsubscribeMessage: { - /** @enum {string} */ - op: "unsubscribe"; - /** @enum {string} */ - event: "market_volume_milestone"; - } & components["schemas"]["MarketVolumeMilestoneFilters"] & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "market_volume_milestone"; - }; - /** - * @description Pushed `market_volume_milestone` alert. The `data` payload matches the corresponding HTTP webhook payload schema. - * @example { - * "event": "market_volume_milestone", - * "timestamp": 1743500000000, - * "data": { - * "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", - * "timeframe": "24h", - * "milestone_usd": 100000, - * "current_volume_usd": 100125, - * "fees": 500, - * "txns": 650 - * } - * } - */ - WsAlertMarketVolumeMilestoneEvent: { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "market_volume_milestone"; - /** - * Format: int64 - * @description Unix timestamp in milliseconds - */ - timestamp: number; - data: components["schemas"]["VolumeMilestonePayload"]; - }; - WsAlertEventVolumeMilestoneSubscribeMessage: { - /** @enum {string} */ - op: "subscribe"; - /** @enum {string} */ - event: "event_volume_milestone"; - } & components["schemas"]["EventVolumeMilestoneFilters"] & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "event_volume_milestone"; - }; - WsAlertEventVolumeMilestoneUnsubscribeMessage: { - /** @enum {string} */ - op: "unsubscribe"; - /** @enum {string} */ - event: "event_volume_milestone"; - } & components["schemas"]["EventVolumeMilestoneFilters"] & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "event_volume_milestone"; - }; - /** - * @description Pushed `event_volume_milestone` alert. The `data` payload matches the corresponding HTTP webhook payload schema. - * @example { - * "event": "event_volume_milestone", - * "timestamp": 1743500000000, - * "data": { - * "event_slug": "test-event-0000000000", - * "timeframe": "24h", - * "milestone_usd": 500000, - * "current_volume_usd": 500250, - * "fees": 2500, - * "txns": 3200 - * } - * } - */ - WsAlertEventVolumeMilestoneEvent: { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "event_volume_milestone"; - /** - * Format: int64 - * @description Unix timestamp in milliseconds - */ - timestamp: number; - data: components["schemas"]["EventVolumeMilestonePayload"]; - }; - WsAlertPositionVolumeMilestoneSubscribeMessage: { - /** @enum {string} */ - op: "subscribe"; - /** @enum {string} */ - event: "position_volume_milestone"; - } & components["schemas"]["PositionVolumeMilestoneFilters"] & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "position_volume_milestone"; - }; - WsAlertPositionVolumeMilestoneUnsubscribeMessage: { - /** @enum {string} */ - op: "unsubscribe"; - /** @enum {string} */ - event: "position_volume_milestone"; - } & components["schemas"]["PositionVolumeMilestoneFilters"] & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "position_volume_milestone"; - }; - /** - * @description Pushed `position_volume_milestone` alert. The `data` payload matches the corresponding HTTP webhook payload schema. - * @example { - * "event": "position_volume_milestone", - * "timestamp": 1743500000000, - * "data": { - * "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", - * "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", - * "outcome": "Yes", - * "outcome_index": 0, - * "timeframe": "24h", - * "milestone_usd": 50000, - * "current_volume_usd": 50125, - * "buy_volume_usd": 30000, - * "sell_volume_usd": 20000, - * "fees": 250, - * "txns": 320, - * "buys": 190, - * "sells": 130 - * } - * } - */ - WsAlertPositionVolumeMilestoneEvent: { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "position_volume_milestone"; - /** - * Format: int64 - * @description Unix timestamp in milliseconds - */ - timestamp: number; - data: components["schemas"]["PositionVolumeMilestonePayload"]; - }; - WsAlertProbabilitySpikeSubscribeMessage: { - /** @enum {string} */ - op: "subscribe"; - /** @enum {string} */ - event: "probability_spike"; - } & components["schemas"]["ProbabilitySpikeFilters"] & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "probability_spike"; - }; - WsAlertProbabilitySpikeUnsubscribeMessage: { - /** @enum {string} */ - op: "unsubscribe"; - /** @enum {string} */ - event: "probability_spike"; - } & components["schemas"]["ProbabilitySpikeFilters"] & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "probability_spike"; - }; - /** - * @description Pushed `probability_spike` alert. The `data` payload matches the corresponding HTTP webhook payload schema. - * @example { - * "event": "probability_spike", - * "timestamp": 1743500000000, - * "data": { - * "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", - * "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", - * "event_slug": "test-event-0000000000", - * "outcome": "Yes", - * "outcome_index": 0, - * "previous_probability": 0.4, - * "current_probability": 0.5, - * "spike_direction": "up", - * "spike_pct": 25 - * } - * } - */ - WsAlertProbabilitySpikeEvent: { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "probability_spike"; - /** - * Format: int64 - * @description Unix timestamp in milliseconds - */ - timestamp: number; - data: components["schemas"]["ProbabilitySpikePayload"]; - }; - WsAlertPriceSpikeSubscribeMessage: { - /** @enum {string} */ - op: "subscribe"; - /** @enum {string} */ - event: "price_spike"; - } & components["schemas"]["PriceSpikeFilters"] & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "price_spike"; - }; - WsAlertPriceSpikeUnsubscribeMessage: { - /** @enum {string} */ - op: "unsubscribe"; - /** @enum {string} */ - event: "price_spike"; - } & components["schemas"]["PriceSpikeFilters"] & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "price_spike"; - }; - /** - * @description Pushed `price_spike` alert. The `data` payload matches the corresponding HTTP webhook payload schema. - * @example { - * "event": "price_spike", - * "timestamp": 1743500000000, - * "data": { - * "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", - * "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", - * "event_slug": "test-event-0000000000", - * "outcome": "Yes", - * "outcome_index": 0, - * "previous_price": 0.4, - * "current_price": 0.5, - * "spike_direction": "up", - * "spike_pct": 25 - * } - * } - */ - WsAlertPriceSpikeEvent: { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "price_spike"; - /** - * Format: int64 - * @description Unix timestamp in milliseconds - */ - timestamp: number; - data: components["schemas"]["PriceSpikePayload"]; - }; - WsAlertMarketVolumeSpikeSubscribeMessage: { - /** @enum {string} */ - op: "subscribe"; - /** @enum {string} */ - event: "market_volume_spike"; - } & components["schemas"]["MarketVolumeSpikeFilters"] & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "market_volume_spike"; - }; - WsAlertMarketVolumeSpikeUnsubscribeMessage: { - /** @enum {string} */ - op: "unsubscribe"; - /** @enum {string} */ - event: "market_volume_spike"; - } & components["schemas"]["MarketVolumeSpikeFilters"] & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "market_volume_spike"; - }; - /** - * @description Pushed `market_volume_spike` alert. The `data` payload matches the corresponding HTTP webhook payload schema. - * @example { - * "event": "market_volume_spike", - * "timestamp": 1743500000000, - * "data": { - * "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", - * "timeframe": "1h", - * "current_volume_usd": 32000, - * "snapshot_volume_usd": 10000, - * "delta_volume_usd": 22000, - * "spike_pct": 220, - * "txns": 480, - * "fees": 160 - * } - * } - */ - WsAlertMarketVolumeSpikeEvent: { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "market_volume_spike"; - /** - * Format: int64 - * @description Unix timestamp in milliseconds - */ - timestamp: number; - data: components["schemas"]["MarketVolumeSpikePayload"]; - }; - WsAlertEventVolumeSpikeSubscribeMessage: { - /** @enum {string} */ - op: "subscribe"; - /** @enum {string} */ - event: "event_volume_spike"; - } & components["schemas"]["EventVolumeSpikeFilters"] & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "event_volume_spike"; - }; - WsAlertEventVolumeSpikeUnsubscribeMessage: { - /** @enum {string} */ - op: "unsubscribe"; - /** @enum {string} */ - event: "event_volume_spike"; - } & components["schemas"]["EventVolumeSpikeFilters"] & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "event_volume_spike"; - }; - /** - * @description Pushed `event_volume_spike` alert. The `data` payload matches the corresponding HTTP webhook payload schema. - * @example { - * "event": "event_volume_spike", - * "timestamp": 1743500000000, - * "data": { - * "event_slug": "test-event-0000000000", - * "timeframe": "1h", - * "current_volume_usd": 140000, - * "snapshot_volume_usd": 50000, - * "delta_volume_usd": 90000, - * "spike_pct": 180, - * "txns": 1100, - * "fees": 700 - * } - * } - */ - WsAlertEventVolumeSpikeEvent: { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "event_volume_spike"; - /** - * Format: int64 - * @description Unix timestamp in milliseconds - */ - timestamp: number; - data: components["schemas"]["EventVolumeSpikePayload"]; - }; - WsAlertPositionVolumeSpikeSubscribeMessage: { - /** @enum {string} */ - op: "subscribe"; - /** @enum {string} */ - event: "position_volume_spike"; - } & components["schemas"]["PositionVolumeSpikeFilters"] & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "position_volume_spike"; - }; - WsAlertPositionVolumeSpikeUnsubscribeMessage: { - /** @enum {string} */ - op: "unsubscribe"; - /** @enum {string} */ - event: "position_volume_spike"; - } & components["schemas"]["PositionVolumeSpikeFilters"] & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "position_volume_spike"; - }; - /** - * @description Pushed `position_volume_spike` alert. The `data` payload matches the corresponding HTTP webhook payload schema. - * @example { - * "event": "position_volume_spike", - * "timestamp": 1743500000000, - * "data": { - * "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", - * "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", - * "outcome": "Yes", - * "outcome_index": 0, - * "timeframe": "1h", - * "current_volume_usd": 20500, - * "snapshot_volume_usd": 5000, - * "delta_volume_usd": 15500, - * "spike_pct": 310, - * "txns": 240, - * "fees": 102.5 - * } - * } - */ - WsAlertPositionVolumeSpikeEvent: { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "position_volume_spike"; - /** - * Format: int64 - * @description Unix timestamp in milliseconds - */ - timestamp: number; - data: components["schemas"]["PositionVolumeSpikePayload"]; - }; - WsAlertCloseToBondSubscribeMessage: ({ - /** @enum {string} */ - op: "subscribe"; - /** @enum {string} */ - event: "close_to_bond"; - } & components["schemas"]["CloseToBondFilters"] & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "close_to_bond"; - }) | unknown | unknown; - WsAlertCloseToBondUnsubscribeMessage: ({ - /** @enum {string} */ - op: "unsubscribe"; - /** @enum {string} */ - event: "close_to_bond"; - } & components["schemas"]["CloseToBondFilters"] & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "close_to_bond"; - }) | unknown | unknown; - /** - * @description Pushed `close_to_bond` alert. The `data` payload matches the corresponding HTTP webhook payload schema. - * @example { - * "event": "close_to_bond", - * "timestamp": 1743500000000, - * "data": { - * "trader": "0x0000000000000000000000000000000000000000", - * "taker": "0x0000000000000000000000000000000000000000", - * "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656", - * "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", - * "outcome": "Yes", - * "outcome_index": 0, - * "question": "Will this test webhook fire correctly?", - * "market_slug": "test-market-0000000000", - * "event_slug": "test-event-0000000000", - * "trade_id": "00000000-0000-0000-0000-000000000000", - * "hash": "0x0000000000000000000000000000000000000000000000000000000000000000", - * "block": 0, - * "confirmed_at": 1700000000, - * "amount_usd": 500, - * "shares_amount": 515.46, - * "fee": 2.5, - * "side": "Buy", - * "price": 0.97, - * "probability": 0.97, - * "bond_side": "high", - * "threshold": 0.95 - * } - * } - */ - WsAlertCloseToBondEvent: { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "close_to_bond"; - /** - * Format: int64 - * @description Unix timestamp in milliseconds - */ - timestamp: number; - data: components["schemas"]["CloseToBondPayload"]; - }; - WsAlertMarketCreatedSubscribeMessage: { - /** @enum {string} */ - op: "subscribe"; - /** @enum {string} */ - event: "market_created"; - } & components["schemas"]["MarketCreatedFilters"] & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "market_created"; - }; - WsAlertMarketCreatedUnsubscribeMessage: { - /** @enum {string} */ - op: "unsubscribe"; - /** @enum {string} */ - event: "market_created"; - } & components["schemas"]["MarketCreatedFilters"] & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "market_created"; - }; - /** - * @description Pushed `market_created` alert. The `data` payload matches the corresponding HTTP webhook payload schema. - * @example { - * "event": "market_created", - * "timestamp": 1743500000000, - * "data": { - * "condition_id": "0x0000000000000000000000000000000000000000000000000000000000000000", - * "market_slug": "test-market-0000000000", - * "event_slug": "test-event-0000000000", - * "event_id": null, - * "event_title": "Test Event 0000", - * "series_slug": null, - * "outcomes": [ - * { - * "index": 0, - * "name": "Yes", - * "position_id": "452312848583266388373324160190187140051835877600158453279131187530910662656" - * }, - * { - * "index": 1, - * "name": "No", - * "position_id": "0" - * } - * ], - * "question": "Will this test webhook fire correctly?", - * "title": "Test Market 0000", - * "description": "A test market for webhook payload verification.", - * "category": "Crypto", - * "tags": [ - * "test", - * "crypto" - * ], - * "image_url": null, - * "neg_risk": false - * } - * } - */ - WsAlertMarketCreatedEvent: { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "market_created"; - /** - * Format: int64 - * @description Unix timestamp in milliseconds - */ - timestamp: number; - data: components["schemas"]["MarketCreatedPayload"]; - }; - WsAlertAssetPriceTickSubscribeMessage: { - /** @enum {string} */ - op: "subscribe"; - /** @enum {string} */ - event: "asset_price_tick"; - } & components["schemas"]["AssetPriceTickFilters"] & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "asset_price_tick"; - }; - WsAlertAssetPriceTickUnsubscribeMessage: { - /** @enum {string} */ - op: "unsubscribe"; - /** @enum {string} */ - event: "asset_price_tick"; - } & components["schemas"]["AssetPriceTickFilters"] & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "asset_price_tick"; - }; - /** - * @description Pushed `asset_price_tick` alert. The `data` payload matches the corresponding HTTP webhook payload schema. - * @example { - * "event": "asset_price_tick", - * "timestamp": 1743500000000, - * "data": { - * "symbol": "BTC", - * "price": 65000, - * "timestamp_ms": 1700000000000 - * } - * } - */ - WsAlertAssetPriceTickEvent: { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "asset_price_tick"; - /** - * Format: int64 - * @description Unix timestamp in milliseconds - */ - timestamp: number; - data: components["schemas"]["AssetPriceTickPayload"]; - }; - WsAlertAssetPriceWindowUpdateSubscribeMessage: { - /** @enum {string} */ - op: "subscribe"; - /** @enum {string} */ - event: "asset_price_window_update"; - } & components["schemas"]["AssetPriceWindowUpdateFilters"] & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "asset_price_window_update"; - }; - WsAlertAssetPriceWindowUpdateUnsubscribeMessage: { - /** @enum {string} */ - op: "unsubscribe"; - /** @enum {string} */ - event: "asset_price_window_update"; - } & components["schemas"]["AssetPriceWindowUpdateFilters"] & { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "asset_price_window_update"; - }; - /** - * @description Pushed `asset_price_window_update` alert. The `data` payload matches the corresponding HTTP webhook payload schema. - * @example { - * "event": "asset_price_window_update", - * "timestamp": 1743500000000, - * "data": { - * "symbol": "BTC", - * "variant": "1h", - * "start_time": 1700000000000, - * "end_time": 1700003600000, - * "open_price": 64800, - * "close_price": 65200, - * "update_type": "close" - * } - * } - */ - WsAlertAssetPriceWindowUpdateEvent: { - /** - * @description discriminator enum property added by openapi-typescript - * @enum {string} - */ - event: "asset_price_window_update"; - /** - * Format: int64 - * @description Unix timestamp in milliseconds - */ - timestamp: number; - data: components["schemas"]["AssetPriceWindowUpdatePayload"]; - }; - /** @description Typed subscribe request for the alerts WebSocket. The request shape depends on `event` and reuses the matching webhook filter schema. */ - WsAlertSubscribeMessage: components["schemas"]["WsAlertTraderFirstTradeSubscribeMessage"] | components["schemas"]["WsAlertTraderNewMarketSubscribeMessage"] | components["schemas"]["WsAlertTraderWhaleTradeSubscribeMessage"] | components["schemas"]["WsAlertTraderNewTradeSubscribeMessage"] | components["schemas"]["WsAlertTraderGlobalPnlSubscribeMessage"] | components["schemas"]["WsAlertTraderMarketPnlSubscribeMessage"] | components["schemas"]["WsAlertTraderEventPnlSubscribeMessage"] | components["schemas"]["WsAlertConditionMetricsSubscribeMessage"] | components["schemas"]["WsAlertEventMetricsSubscribeMessage"] | components["schemas"]["WsAlertPositionMetricsSubscribeMessage"] | components["schemas"]["WsAlertMarketVolumeMilestoneSubscribeMessage"] | components["schemas"]["WsAlertEventVolumeMilestoneSubscribeMessage"] | components["schemas"]["WsAlertPositionVolumeMilestoneSubscribeMessage"] | components["schemas"]["WsAlertProbabilitySpikeSubscribeMessage"] | components["schemas"]["WsAlertPriceSpikeSubscribeMessage"] | components["schemas"]["WsAlertMarketVolumeSpikeSubscribeMessage"] | components["schemas"]["WsAlertEventVolumeSpikeSubscribeMessage"] | components["schemas"]["WsAlertPositionVolumeSpikeSubscribeMessage"] | components["schemas"]["WsAlertCloseToBondSubscribeMessage"] | components["schemas"]["WsAlertMarketCreatedSubscribeMessage"] | components["schemas"]["WsAlertAssetPriceTickSubscribeMessage"] | components["schemas"]["WsAlertAssetPriceWindowUpdateSubscribeMessage"]; - /** @description Typed unsubscribe request for the alerts WebSocket. The request shape depends on `event` and must match the original subscription filters. */ - WsAlertUnsubscribeMessage: components["schemas"]["WsAlertTraderFirstTradeUnsubscribeMessage"] | components["schemas"]["WsAlertTraderNewMarketUnsubscribeMessage"] | components["schemas"]["WsAlertTraderWhaleTradeUnsubscribeMessage"] | components["schemas"]["WsAlertTraderNewTradeUnsubscribeMessage"] | components["schemas"]["WsAlertTraderGlobalPnlUnsubscribeMessage"] | components["schemas"]["WsAlertTraderMarketPnlUnsubscribeMessage"] | components["schemas"]["WsAlertTraderEventPnlUnsubscribeMessage"] | components["schemas"]["WsAlertConditionMetricsUnsubscribeMessage"] | components["schemas"]["WsAlertEventMetricsUnsubscribeMessage"] | components["schemas"]["WsAlertPositionMetricsUnsubscribeMessage"] | components["schemas"]["WsAlertMarketVolumeMilestoneUnsubscribeMessage"] | components["schemas"]["WsAlertEventVolumeMilestoneUnsubscribeMessage"] | components["schemas"]["WsAlertPositionVolumeMilestoneUnsubscribeMessage"] | components["schemas"]["WsAlertProbabilitySpikeUnsubscribeMessage"] | components["schemas"]["WsAlertPriceSpikeUnsubscribeMessage"] | components["schemas"]["WsAlertMarketVolumeSpikeUnsubscribeMessage"] | components["schemas"]["WsAlertEventVolumeSpikeUnsubscribeMessage"] | components["schemas"]["WsAlertPositionVolumeSpikeUnsubscribeMessage"] | components["schemas"]["WsAlertCloseToBondUnsubscribeMessage"] | components["schemas"]["WsAlertMarketCreatedUnsubscribeMessage"] | components["schemas"]["WsAlertAssetPriceTickUnsubscribeMessage"] | components["schemas"]["WsAlertAssetPriceWindowUpdateUnsubscribeMessage"]; - /** @description Typed pushed-event envelope for the alerts WebSocket. The `data` payload depends on `event` and matches the corresponding HTTP webhook payload schema. */ - WsAlertEventPayload: components["schemas"]["WsAlertTraderFirstTradeEvent"] | components["schemas"]["WsAlertTraderNewMarketEvent"] | components["schemas"]["WsAlertTraderWhaleTradeEvent"] | components["schemas"]["WsAlertTraderNewTradeEvent"] | components["schemas"]["WsAlertTraderGlobalPnlEvent"] | components["schemas"]["WsAlertTraderMarketPnlEvent"] | components["schemas"]["WsAlertTraderEventPnlEvent"] | components["schemas"]["WsAlertConditionMetricsEvent"] | components["schemas"]["WsAlertEventMetricsEvent"] | components["schemas"]["WsAlertPositionMetricsEvent"] | components["schemas"]["WsAlertMarketVolumeMilestoneEvent"] | components["schemas"]["WsAlertEventVolumeMilestoneEvent"] | components["schemas"]["WsAlertPositionVolumeMilestoneEvent"] | components["schemas"]["WsAlertProbabilitySpikeEvent"] | components["schemas"]["WsAlertPriceSpikeEvent"] | components["schemas"]["WsAlertMarketVolumeSpikeEvent"] | components["schemas"]["WsAlertEventVolumeSpikeEvent"] | components["schemas"]["WsAlertPositionVolumeSpikeEvent"] | components["schemas"]["WsAlertCloseToBondEvent"] | components["schemas"]["WsAlertMarketCreatedEvent"] | components["schemas"]["WsAlertAssetPriceTickEvent"] | components["schemas"]["WsAlertAssetPriceWindowUpdateEvent"]; }; responses: never; parameters: never; @@ -3456,55 +919,3 @@ export interface components { } export type $defs = Record; export type operations = Record; - -export interface WsAlertSubscribeMap { - trader_first_trade: components["schemas"]["WsAlertTraderFirstTradeSubscribeMessage"]; - trader_new_market: components["schemas"]["WsAlertTraderNewMarketSubscribeMessage"]; - trader_whale_trade: components["schemas"]["WsAlertTraderWhaleTradeSubscribeMessage"]; - trader_new_trade: components["schemas"]["WsAlertTraderNewTradeSubscribeMessage"]; - trader_global_pnl: components["schemas"]["WsAlertTraderGlobalPnlSubscribeMessage"]; - trader_market_pnl: components["schemas"]["WsAlertTraderMarketPnlSubscribeMessage"]; - trader_event_pnl: components["schemas"]["WsAlertTraderEventPnlSubscribeMessage"]; - condition_metrics: components["schemas"]["WsAlertConditionMetricsSubscribeMessage"]; - event_metrics: components["schemas"]["WsAlertEventMetricsSubscribeMessage"]; - position_metrics: components["schemas"]["WsAlertPositionMetricsSubscribeMessage"]; - market_volume_milestone: components["schemas"]["WsAlertMarketVolumeMilestoneSubscribeMessage"]; - event_volume_milestone: components["schemas"]["WsAlertEventVolumeMilestoneSubscribeMessage"]; - position_volume_milestone: components["schemas"]["WsAlertPositionVolumeMilestoneSubscribeMessage"]; - probability_spike: components["schemas"]["WsAlertProbabilitySpikeSubscribeMessage"]; - price_spike: components["schemas"]["WsAlertPriceSpikeSubscribeMessage"]; - market_volume_spike: components["schemas"]["WsAlertMarketVolumeSpikeSubscribeMessage"]; - event_volume_spike: components["schemas"]["WsAlertEventVolumeSpikeSubscribeMessage"]; - position_volume_spike: components["schemas"]["WsAlertPositionVolumeSpikeSubscribeMessage"]; - close_to_bond: components["schemas"]["WsAlertCloseToBondSubscribeMessage"]; - market_created: components["schemas"]["WsAlertMarketCreatedSubscribeMessage"]; - asset_price_tick: components["schemas"]["WsAlertAssetPriceTickSubscribeMessage"]; - asset_price_window_update: components["schemas"]["WsAlertAssetPriceWindowUpdateSubscribeMessage"]; -} - -export interface WsAlertEventDataMap { - trader_first_trade: components["schemas"]["FirstTradePayload"]; - trader_new_market: components["schemas"]["NewMarketPayload"]; - trader_whale_trade: components["schemas"]["WhaleTradePayload"]; - trader_new_trade: components["schemas"]["NewTradePayload"]; - trader_global_pnl: components["schemas"]["GlobalPnlPayload"]; - trader_market_pnl: components["schemas"]["MarketPnlPayload"]; - trader_event_pnl: components["schemas"]["EventPnlPayload"]; - condition_metrics: components["schemas"]["ConditionMetricsPayload"]; - event_metrics: components["schemas"]["EventMetricsPayload"]; - position_metrics: components["schemas"]["PositionMetricsPayload"]; - market_volume_milestone: components["schemas"]["VolumeMilestonePayload"]; - event_volume_milestone: components["schemas"]["EventVolumeMilestonePayload"]; - position_volume_milestone: components["schemas"]["PositionVolumeMilestonePayload"]; - probability_spike: components["schemas"]["ProbabilitySpikePayload"]; - price_spike: components["schemas"]["PriceSpikePayload"]; - market_volume_spike: components["schemas"]["MarketVolumeSpikePayload"]; - event_volume_spike: components["schemas"]["EventVolumeSpikePayload"]; - position_volume_spike: components["schemas"]["PositionVolumeSpikePayload"]; - close_to_bond: components["schemas"]["CloseToBondPayload"]; - market_created: components["schemas"]["MarketCreatedPayload"]; - asset_price_tick: components["schemas"]["AssetPriceTickPayload"]; - asset_price_window_update: components["schemas"]["AssetPriceWindowUpdatePayload"]; -} - -export type WsAlertEventName = keyof WsAlertSubscribeMap; diff --git a/src/types/http.ts b/src/types/http.ts index 7bc5914..adeebd9 100644 --- a/src/types/http.ts +++ b/src/types/http.ts @@ -2,6 +2,7 @@ export interface RetryConfig { maxRetries?: number; initialDelayMs?: number; maxDelayMs?: number; + maxPendingMessages?: number; } export interface RequestHookInfo { diff --git a/src/types/index.ts b/src/types/index.ts index 24b74fb..6ae04b2 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -12,10 +12,13 @@ export type { operations as WebhookOperations, paths as WebhookPaths, } from "../generated/webhooks.js"; -export type { WsSchemas } from "./ws-helpers.js"; +export type { WsSchemas, WsAlertSchemas } from "./ws-helpers.js"; export type { components as WsComponents, } from "../generated/ws.js"; +export type { + components as WsAlertComponents, +} from "../generated/ws-alerts.js"; import type { Schemas, OperationQuery } from "./helpers.js"; import type { WebhookSchemas, WebhookOperationQuery, WebhookOperationRequestBody } from "./webhook-helpers.js"; @@ -468,6 +471,9 @@ export type { WsSubscriptionMap, WsSubscribeResponseMap, TradesSubscribeFilters, + WsTradeType, + WsTradeStatus, + WsAssetTimeframe, AssetPricesSubscribeFilters, AssetWindowUpdatesSubscribeFilters, MarketMetricsSubscribeFilters, diff --git a/src/types/ws-helpers.ts b/src/types/ws-helpers.ts index 7e9c9a3..2dafb5e 100644 --- a/src/types/ws-helpers.ts +++ b/src/types/ws-helpers.ts @@ -1,4 +1,11 @@ -import type { components, WsAlertSubscribeMap, WsAlertEventDataMap, WsAlertEventName } from "../generated/ws.js"; +import type { components } from "../generated/ws.js"; +import type { + components as alertComponents, + WsAlertSubscribeMap, + WsAlertEventDataMap, + WsAlertEventName, +} from "../generated/ws-alerts.js"; export type WsSchemas = components["schemas"]; +export type WsAlertSchemas = alertComponents["schemas"]; export type { WsAlertSubscribeMap, WsAlertEventDataMap, WsAlertEventName }; diff --git a/src/types/ws.ts b/src/types/ws.ts index 5042da6..5f13ff4 100644 --- a/src/types/ws.ts +++ b/src/types/ws.ts @@ -1,11 +1,18 @@ import type { RetryConfig } from "./http.js"; -import type { WsSchemas, WsAlertSubscribeMap, WsAlertEventDataMap, WsAlertEventName } from "./ws-helpers.js"; +import type { + WsSchemas, + WsAlertSchemas, + WsAlertSubscribeMap, + WsAlertEventDataMap, + WsAlertEventName, +} from "./ws-helpers.js"; export type ConnectionState = "disconnected" | "connecting" | "connected" | "reconnecting"; export interface StructWebSocketConfig { apiKey: string; jwt?: string; + getJwt?: () => string | undefined; baseUrl?: string; reconnect?: RetryConfig; subscribeTimeout?: number; @@ -24,7 +31,7 @@ export type WsRoomId = | "polymarket_order_book" | "polymarket_clob_rewards"; -export type WsFiltersOptionalRoom = "polymarket_asset_prices" | "polymarket_clob_rewards"; +export type WsFiltersOptionalRoom = "polymarket_trades" | "polymarket_asset_prices" | "polymarket_clob_rewards"; export type WsFiltersRequiredRoom = Exclude; export type TradesSubscribeFilters = Omit; @@ -34,12 +41,15 @@ export type MarketMetricsSubscribeFilters = Omit; export type PositionMetricsSubscribeFilters = Omit; export type TraderPnlSubscribeFilters = Omit; -export type AccountsSubscribeFilters = Pick & - Partial>; +export type AccountsSubscribeFilters = Omit; export type OrderBookSubscribeFilters = Omit; export type TraderPositionsSubscribeFilters = Omit; export type ClobRewardsSubscribeFilters = Omit; +export type WsTradeType = NonNullable[number]; +export type WsTradeStatus = NonNullable; +export type WsAssetTimeframe = NonNullable[number]; + export type TradeStreamEvent = WsSchemas["TradeStreamEvent"]; export type AssetPriceTickEvent = WsSchemas["AssetPriceTickEvent"]; export type AssetPriceWindowUpdateEvent = WsSchemas["AssetPriceWindowUpdateEvent"]; @@ -59,13 +69,13 @@ export type TraderPositionUpdateEvent = WsSchemas["TraderPositionUpdateEvent"]; export type TraderPositionsSubscribeResponse = WsSchemas["TraderPositionsSubscribeResponse"]; export type ClobRewardsUpdateEvent = WsSchemas["ClobRewardsUpdateEvent"]; export type ClobRewardsSubscribeResponse = WsSchemas["ClobRewardsSubscribeResponse"]; -export type WsAlertSubscribeMessage = WsSchemas["WsAlertSubscribeMessage"]; -export type WsAlertUnsubscribeMessage = WsSchemas["WsAlertUnsubscribeMessage"]; -export type WsAlertEventPayload = WsSchemas["WsAlertEventPayload"]; -export type WsAlertSubscribedResponse = WsSchemas["WsAlertSubscribedResponse"]; -export type WsAlertUnsubscribedResponse = WsSchemas["WsAlertUnsubscribedResponse"]; -export type WsAlertErrorResponse = WsSchemas["WsAlertErrorResponse"]; -export type WsAlertEventType = WsSchemas["WsAlertEventType"]; +export type WsAlertSubscribeMessage = WsAlertSchemas["WsAlertSubscribeMessage"]; +export type WsAlertUnsubscribeMessage = WsAlertSchemas["WsAlertUnsubscribeMessage"]; +export type WsAlertEventPayload = WsAlertSchemas["WsAlertEventPayload"]; +export type WsAlertSubscribedResponse = WsAlertSchemas["WsAlertSubscribedResponse"]; +export type WsAlertUnsubscribedResponse = WsAlertSchemas["WsAlertUnsubscribedResponse"]; +export type WsAlertErrorResponse = WsAlertSchemas["WsAlertErrorResponse"]; +export type WsAlertEventType = WsAlertSchemas["WsAlertEventType"]; export type { WsAlertSubscribeMap, WsAlertEventDataMap, WsAlertEventName }; export type TradesStreamSubscribeResponse = WsSchemas["TradesStreamSubscribeResponse"]; @@ -98,7 +108,10 @@ export interface WebSocketEventMap { connected: void; disconnected: { code: number; reason: string }; reconnecting: { attempt: number }; + reconnect_failed: Error; + auth_failed: Error; error: Error; + warning: Error; } export interface WsSubscriptionMap { @@ -135,5 +148,8 @@ export type AlertsWebSocketEventMap = { connected: void; disconnected: { code: number; reason: string }; reconnecting: { attempt: number }; + reconnect_failed: Error; + auth_failed: Error; error: Error; + warning: Error; }; diff --git a/src/ws-alerts.ts b/src/ws-alerts.ts index 2cb7d13..2c13a19 100644 --- a/src/ws-alerts.ts +++ b/src/ws-alerts.ts @@ -1,4 +1,4 @@ -import { WebSocketTransport } from "./ws-transport.js"; +import { WebSocketTransport, buildWebSocketUrl } from "./ws-transport.js"; import { WebSocketError } from "./errors.js"; import type { ConnectionState, @@ -17,24 +17,29 @@ type Listener = (payload: T) => void; interface PendingSubscribe { resolve: (data: unknown) => void; reject: (err: Error) => void; - timer: ReturnType; + timer: ReturnType | null; } export class StructAlertsWebSocket { private readonly transport: WebSocketTransport; - private readonly listeners = new Map>(); + private readonly listeners = new Map>>(); private readonly subscriptions = new Map>(); private readonly pendingSubscribes = new Map(); private readonly subscribeTimeout: number; private pingTimer: ReturnType | null = null; + private pongTimer: ReturnType | null = null; + private isEmittingListenerError = false; constructor(config: StructWebSocketConfig) { this.subscribeTimeout = config.subscribeTimeout ?? DEFAULT_SUBSCRIBE_TIMEOUT_MS; - const base = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, ""); - const url = `${base}/ws/alerts?api-key=${encodeURIComponent(config.apiKey)}`; + const getUrl = () => buildWebSocketUrl("/ws/alerts", { + apiKey: config.apiKey, + jwt: config.getJwt?.() ?? config.jwt, + baseUrl: config.baseUrl, + }, DEFAULT_BASE_URL); this.transport = new WebSocketTransport( - url, + getUrl, config.reconnect ?? {}, { onOpen: () => this.handleOpen(), @@ -42,6 +47,9 @@ export class StructAlertsWebSocket { onError: (error) => this.emit("error", error), onMessage: (data) => this.handleMessage(data), onReconnecting: (attempt) => this.emit("reconnecting", { attempt }), + onReconnectFailed: (error) => this.emit("reconnect_failed", error), + onAuthFailed: (error) => this.emit("auth_failed", error), + onWarning: (warning) => this.emit("warning", warning), }, ); } @@ -57,7 +65,7 @@ export class StructAlertsWebSocket { disconnect(): void { this.stopPing(); for (const [, pending] of this.pendingSubscribes) { - clearTimeout(pending.timer); + this.clearSubscribeTimer(pending); pending.reject(new WebSocketError("Disconnected")); } this.pendingSubscribes.clear(); @@ -100,28 +108,26 @@ export class StructAlertsWebSocket { filters: Omit, ): Promise { const message = { op: "subscribe", event, ...filters } as Record; - this.subscriptions.set(event, message); - this.rebuildReplay(); - - this.transport.send(message); const existing = this.pendingSubscribes.get(event); if (existing) { - clearTimeout(existing.timer); + this.clearSubscribeTimer(existing); existing.reject(new WebSocketError("Superseded by new subscription")); } - return new Promise((resolve, reject) => { - const timer = setTimeout(() => { - this.pendingSubscribes.delete(event); - reject(new WebSocketError(`Subscribe to alert ${event} timed out`)); - }, this.subscribeTimeout); + this.subscriptions.set(event, message); + this.rebuildReplay(); - this.pendingSubscribes.set(event, { + return new Promise((resolve, reject) => { + const pending: PendingSubscribe = { resolve: resolve as (data: unknown) => void, reject, - timer, - }); + timer: null, + }; + this.pendingSubscribes.set(event, pending); + if (this.sendSubscription(message)) { + this.armSubscribeTimer(event, pending); + } }); } @@ -131,14 +137,16 @@ export class StructAlertsWebSocket { const pending = this.pendingSubscribes.get(event); if (pending) { - clearTimeout(pending.timer); + this.clearSubscribeTimer(pending); pending.reject(new WebSocketError("Unsubscribed")); this.pendingSubscribes.delete(event); } - this.transport.send({ ...sub, op: "unsubscribe" }); this.subscriptions.delete(event); this.rebuildReplay(); + if (this.state === "connected") { + this.transport.sendNow({ ...sub, op: "unsubscribe" }); + } } private rebuildReplay(): void { @@ -150,28 +158,42 @@ export class StructAlertsWebSocket { private handleOpen(): void { this.startPing(); + this.restartPendingSubscribes(); this.emit("connected", undefined as never); } private handleClose(code: number, reason: string): void { this.stopPing(); + this.pausePendingSubscribes(); this.emit("disconnected", { code, reason }); } private handleMessage(raw: unknown): void { - const msg = raw as { op?: string; event?: string; error?: string; subscription_id?: string; timestamp?: number; data?: unknown }; + const msg = raw as { op?: string; type?: string; event?: string; error?: string; subscription_id?: string; timestamp?: number; data?: unknown }; if (!msg || typeof msg !== "object") return; - if (msg.op === "pong") return; + if (msg.op === "pong" || msg.type === "pong") { + this.clearPongTimer(); + return; + } if (msg.error) { - this.emit("error", new WebSocketError(msg.error)); + const error = new WebSocketError(msg.error); + if (msg.event) { + const pending = this.pendingSubscribes.get(msg.event as WsAlertEventName); + if (pending) { + this.clearSubscribeTimer(pending); + this.pendingSubscribes.delete(msg.event as WsAlertEventName); + pending.reject(error); + } + } + this.emit("error", error); return; } if (msg.op === "subscribed" && msg.event) { const pending = this.pendingSubscribes.get(msg.event as WsAlertEventName); if (pending) { - clearTimeout(pending.timer); + this.clearSubscribeTimer(pending); this.pendingSubscribes.delete(msg.event as WsAlertEventName); pending.resolve({ op: "subscribed", event: msg.event, subscription_id: msg.subscription_id }); } @@ -195,14 +217,18 @@ export class StructAlertsWebSocket { for (const fn of set) { try { (fn as Listener)(payload); - } catch {} + } catch (error) { + this.handleListenerError(error); + } } } private startPing(): void { this.stopPing(); this.pingTimer = setInterval(() => { - this.transport.send({ type: "ping" }); + if (this.transport.sendNow({ type: "ping" })) { + this.armPongTimer(); + } }, PING_INTERVAL_MS); } @@ -211,5 +237,72 @@ export class StructAlertsWebSocket { clearInterval(this.pingTimer); this.pingTimer = null; } + this.clearPongTimer(); + } + + private sendSubscription(message: Record): boolean { + if (this.state !== "connected") return false; + return this.transport.sendNow(message); + } + + private restartPendingSubscribes(): void { + for (const [event, pending] of this.pendingSubscribes) { + if (pending.timer === null) { + this.armSubscribeTimer(event, pending); + } + } + } + + private pausePendingSubscribes(): void { + for (const [, pending] of this.pendingSubscribes) { + this.clearSubscribeTimer(pending); + } + } + + private armSubscribeTimer(event: WsAlertEventName, pending: PendingSubscribe): void { + this.clearSubscribeTimer(pending); + pending.timer = setTimeout(() => { + pending.timer = null; + this.pendingSubscribes.delete(event); + pending.reject(new WebSocketError(`Subscribe to alert ${event} timed out`)); + }, this.subscribeTimeout); + } + + private clearSubscribeTimer(pending: PendingSubscribe): void { + if (pending.timer !== null) { + clearTimeout(pending.timer); + pending.timer = null; + } + } + + private armPongTimer(): void { + if (this.pongTimer !== null) return; + this.pongTimer = setTimeout(() => { + this.pongTimer = null; + this.transport.close(4000, "pong timeout"); + }, PING_INTERVAL_MS * 2); + } + + private clearPongTimer(): void { + if (this.pongTimer !== null) { + clearTimeout(this.pongTimer); + this.pongTimer = null; + } + } + + private handleListenerError(error: unknown): void { + const normalizedError = error instanceof Error + ? error + : new WebSocketError("WebSocket listener threw", { cause: error }); + if (!this.isEmittingListenerError && (this.listeners.get("error")?.size ?? 0) > 0) { + this.isEmittingListenerError = true; + try { + this.emit("error", normalizedError); + return; + } finally { + this.isEmittingListenerError = false; + } + } + console.error(normalizedError); } } diff --git a/src/ws-transport.ts b/src/ws-transport.ts index 8cb7761..9cd1954 100644 --- a/src/ws-transport.ts +++ b/src/ws-transport.ts @@ -4,6 +4,33 @@ import type { RetryConfig } from "./types/http.js"; const DEFAULT_INITIAL_DELAY_MS = 1_000; const DEFAULT_MAX_DELAY_MS = 30_000; +const DEFAULT_MAX_PENDING_MESSAGES = 256; +const AUTH_FAILURE_CLOSE_CODES = new Set([1008, 4401]); + +interface QueuedMessage { + message: Record; +} + +interface ReplayMessageGroup { + messages: QueuedMessage[]; +} + +interface ConnectWaiter { + resolve: () => void; + reject: (err: Error) => void; +} + +export function buildWebSocketUrl( + path: string, + config: { apiKey: string; jwt?: string; baseUrl?: string }, + defaultBaseUrl: string, +): string { + const base = (config.baseUrl ?? defaultBaseUrl).replace(/\/+$/, ""); + const wsBase = base.replace(/^https:\/\//, "wss://").replace(/^http:\/\//, "ws://"); + const params = new URLSearchParams({ "api-key": config.apiKey }); + if (config.jwt) params.set("token", config.jwt); + return `${wsBase}${path}?${params.toString()}`; +} export interface WebSocketTransportCallbacks { onOpen: () => void; @@ -11,6 +38,9 @@ export interface WebSocketTransportCallbacks { onError: (error: Error) => void; onMessage: (data: unknown) => void; onReconnecting: (attempt: number) => void; + onReconnectFailed: (error: Error) => void; + onAuthFailed: (error: WebSocketClosedError) => void; + onWarning: (warning: Error) => void; } export class WebSocketTransport { @@ -19,16 +49,15 @@ export class WebSocketTransport { private reconnectTimer: ReturnType | null = null; private reconnectAttempt = 0; private intentionalClose = false; - private connectResolve: (() => void) | null = null; - private connectReject: ((err: Error) => void) | null = null; - private readonly pendingMessages: Record[] = []; - private readonly replayMessages: Record[] = []; - private readonly url: string; + private readonly connectWaiters = new Set(); + private readonly pendingMessages: QueuedMessage[] = []; + private readonly replayMessages: ReplayMessageGroup[] = []; + private readonly getUrl: () => string; private readonly retry: RetryConfig; private readonly callbacks: WebSocketTransportCallbacks; - constructor(url: string, retry: RetryConfig, callbacks: WebSocketTransportCallbacks) { - this.url = url; + constructor(url: string | (() => string), retry: RetryConfig, callbacks: WebSocketTransportCallbacks) { + this.getUrl = typeof url === "function" ? url : () => url; this.retry = retry; this.callbacks = callbacks; } @@ -39,24 +68,14 @@ export class WebSocketTransport { connect(): Promise { if (this._state === "connected") return Promise.resolve(); + const promise = this.createConnectPromise(); if (this._state === "connecting" || this._state === "reconnecting") { - return new Promise((resolve, reject) => { - const prevResolve = this.connectResolve; - const prevReject = this.connectReject; - this.connectResolve = () => { prevResolve?.(); resolve(); }; - this.connectReject = (err) => { prevReject?.(err); reject(err); }; - }); + return promise; } this.intentionalClose = false; this.clearReconnectTimer(); this.setState("connecting"); - - const promise = new Promise((resolve, reject) => { - this.connectResolve = resolve; - this.connectReject = reject; - }); - this.createSocket(); return promise; } @@ -66,7 +85,7 @@ export class WebSocketTransport { this.clearReconnectTimer(); this.pendingMessages.length = 0; this.replayMessages.length = 0; - this.resolveConnect(new WebSocketClosedError(1000, "client disconnect")); + this.rejectConnect(new WebSocketClosedError(1000, "client disconnect")); if (this.ws) { this.ws.close(1000, "client disconnect"); this.ws = null; @@ -74,39 +93,59 @@ export class WebSocketTransport { this.setState("disconnected"); } - send(message: Record): void { - if (this._state === "connected" && this.ws?.readyState === WebSocket.OPEN) { - this.ws.send(JSON.stringify(message)); - } else { - this.pendingMessages.push(message); - } + send(message: Record): boolean { + const queuedMessage: QueuedMessage = { message }; + if (this.sendMessage(queuedMessage)) return true; + this.enqueueMessage(this.pendingMessages, queuedMessage, "pending"); + return false; + } + + sendNow(message: Record): boolean { + return this.sendMessage({ message }); } addReplayMessage(message: Record): void { - this.replayMessages.push(message); + this.addReplayMessages([message]); + } + + addReplayMessages(messages: Record[]): void { + this.enqueueReplayMessages(messages.map((message) => ({ message }))); } clearReplayMessages(): void { this.replayMessages.length = 0; } - private resolveConnect(error?: Error): void { - if (error) { - this.connectReject?.(error); - } else { - this.connectResolve?.(); + close(code: number, reason: string): void { + this.ws?.close(code, reason); + } + + private createConnectPromise(): Promise { + return new Promise((resolve, reject) => { + this.connectWaiters.add({ resolve, reject }); + }); + } + + private resolveConnect(): void { + for (const waiter of this.connectWaiters) { + waiter.resolve(); } - this.connectResolve = null; - this.connectReject = null; + this.connectWaiters.clear(); + } + + private rejectConnect(error: Error): void { + for (const waiter of this.connectWaiters) { + waiter.reject(error); + } + this.connectWaiters.clear(); } private createSocket(): void { try { - this.ws = new WebSocket(this.url); + this.ws = new WebSocket(this.getUrl()); } catch (err) { const error = new WebSocketError("Failed to create WebSocket", { cause: err }); this.callbacks.onError(error); - this.resolveConnect(error); this.scheduleReconnect(); return; } @@ -127,8 +166,15 @@ export class WebSocketTransport { this.callbacks.onClose(event.code, event.reason); return; } - this.resolveConnect(new WebSocketClosedError(event.code, event.reason)); + + const error = new WebSocketClosedError(event.code, event.reason); this.callbacks.onClose(event.code, event.reason); + if (this.isAuthFailure(event.code)) { + this.setState("disconnected"); + this.rejectConnect(error); + this.callbacks.onAuthFailed(error); + return; + } this.scheduleReconnect(); }; @@ -147,29 +193,26 @@ export class WebSocketTransport { } private replaySubscriptions(): void { - for (const msg of this.replayMessages) { - if (this.ws?.readyState === WebSocket.OPEN) { - this.ws.send(JSON.stringify(msg)); + for (const replayGroup of this.replayMessages) { + for (const queuedMessage of replayGroup.messages) { + this.sendMessage(queuedMessage); } } } private flushPendingMessages(): void { while (this.pendingMessages.length > 0) { - const msg = this.pendingMessages.shift()!; - if (this.ws?.readyState === WebSocket.OPEN) { - this.ws.send(JSON.stringify(msg)); - } + this.sendMessage(this.pendingMessages.shift()!); } } private scheduleReconnect(): void { const maxRetries = this.retry.maxRetries ?? Infinity; if (this.reconnectAttempt >= maxRetries) { + const error = new WebSocketClosedError(1006, "Max reconnection attempts reached"); this.setState("disconnected"); - this.callbacks.onError( - new WebSocketClosedError(1006, "Max reconnection attempts reached"), - ); + this.rejectConnect(error); + this.callbacks.onReconnectFailed(error); return; } @@ -196,6 +239,42 @@ export class WebSocketTransport { } } + private sendMessage(queuedMessage: QueuedMessage): boolean { + if (this.ws?.readyState !== WebSocket.OPEN) return false; + this.ws.send(JSON.stringify(queuedMessage.message)); + return true; + } + + private enqueueMessage(queue: QueuedMessage[], queuedMessage: QueuedMessage, queueName: "pending" | "replay"): void { + queue.push(queuedMessage); + const maxPendingMessages = this.retry.maxPendingMessages ?? DEFAULT_MAX_PENDING_MESSAGES; + if (queue.length > maxPendingMessages) { + queue.shift(); + this.callbacks.onWarning( + new WebSocketError( + `WebSocket ${queueName} queue exceeded ${maxPendingMessages} messages; dropped oldest message`, + ), + ); + } + } + + private enqueueReplayMessages(messages: QueuedMessage[]): void { + this.replayMessages.push({ messages }); + const maxPendingMessages = this.retry.maxPendingMessages ?? DEFAULT_MAX_PENDING_MESSAGES; + if (this.replayMessages.length > maxPendingMessages) { + this.replayMessages.shift(); + this.callbacks.onWarning( + new WebSocketError( + `WebSocket replay queue exceeded ${maxPendingMessages} entries; dropped oldest replay entry`, + ), + ); + } + } + + private isAuthFailure(code: number): boolean { + return AUTH_FAILURE_CLOSE_CODES.has(code); + } + private setState(state: ConnectionState): void { this._state = state; } diff --git a/src/ws.ts b/src/ws.ts index c41b9cc..c2b86d3 100644 --- a/src/ws.ts +++ b/src/ws.ts @@ -1,4 +1,4 @@ -import { WebSocketTransport } from "./ws-transport.js"; +import { WebSocketTransport, buildWebSocketUrl } from "./ws-transport.js"; import { WebSocketError } from "./errors.js"; import type { ConnectionState, @@ -20,27 +20,29 @@ type Listener = (payload: T) => void; interface PendingSubscribe { resolve: (data: unknown) => void; reject: (err: Error) => void; - timer: ReturnType; + timer: ReturnType | null; } export class StructWebSocket { private readonly transport: WebSocketTransport; - private readonly listeners = new Map>(); + private readonly listeners = new Map>>(); private readonly subscriptions = new Map>(); private readonly pendingSubscribes = new Map(); private readonly subscribeTimeout: number; private pingTimer: ReturnType | null = null; + private pongTimer: ReturnType | null = null; + private isEmittingListenerError = false; constructor(config: StructWebSocketConfig) { this.subscribeTimeout = config.subscribeTimeout ?? DEFAULT_SUBSCRIBE_TIMEOUT_MS; - const base = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, ""); - const wsBase = base.replace(/^https:\/\//, "wss://").replace(/^http:\/\//, "ws://"); - const url = config.jwt - ? `${wsBase}/ws?api-key=${encodeURIComponent(config.apiKey)}&token=${encodeURIComponent(config.jwt)}` - : `${wsBase}/ws?api-key=${encodeURIComponent(config.apiKey)}`; + const getUrl = () => buildWebSocketUrl("/ws", { + apiKey: config.apiKey, + jwt: config.getJwt?.() ?? config.jwt, + baseUrl: config.baseUrl, + }, DEFAULT_BASE_URL); this.transport = new WebSocketTransport( - url, + getUrl, config.reconnect ?? {}, { onOpen: () => this.handleOpen(), @@ -48,6 +50,9 @@ export class StructWebSocket { onError: (error) => this.emit("error", error), onMessage: (data) => this.handleMessage(data), onReconnecting: (attempt) => this.emit("reconnecting", { attempt }), + onReconnectFailed: (error) => this.emit("reconnect_failed", error), + onAuthFailed: (error) => this.emit("auth_failed", error), + onWarning: (warning) => this.emit("warning", warning), }, ); } @@ -63,7 +68,7 @@ export class StructWebSocket { disconnect(): void { this.stopPing(); for (const [, pending] of this.pendingSubscribes) { - clearTimeout(pending.timer); + this.clearSubscribeTimer(pending); pending.reject(new WebSocketError("Disconnected")); } this.pendingSubscribes.clear(); @@ -106,34 +111,26 @@ export class StructWebSocket { subscribe(room: R, filters?: WsSubscriptionMap[R]): Promise { const resolvedFilters = (filters ?? {}) as Record; const isNewRoom = !this.subscriptions.has(room); - this.subscriptions.set(room, resolvedFilters); - this.rebuildReplay(); - - if (isNewRoom) { - this.transport.send({ type: "join_room", payload: { room_id: room } }); - } - this.transport.send({ - type: "room_message", - payload: { room_id: room, message: { action: "subscribe", ...resolvedFilters } }, - }); const existing = this.pendingSubscribes.get(room); if (existing) { - clearTimeout(existing.timer); + this.clearSubscribeTimer(existing); existing.reject(new WebSocketError("Superseded by new subscription")); } - return new Promise((resolve, reject) => { - const timer = setTimeout(() => { - this.pendingSubscribes.delete(room); - reject(new WebSocketError(`Subscribe to ${room} timed out`)); - }, this.subscribeTimeout); + this.subscriptions.set(room, resolvedFilters); + this.rebuildReplay(); - this.pendingSubscribes.set(room, { + return new Promise((resolve, reject) => { + const pending: PendingSubscribe = { resolve: resolve as (data: unknown) => void, reject, - timer, - }); + timer: null, + }; + this.pendingSubscribes.set(room, pending); + if (this.sendSubscription(room, resolvedFilters, isNewRoom)) { + this.armSubscribeTimer(room, pending); + } }); } @@ -142,52 +139,68 @@ export class StructWebSocket { const pending = this.pendingSubscribes.get(room); if (pending) { - clearTimeout(pending.timer); + this.clearSubscribeTimer(pending); pending.reject(new WebSocketError("Unsubscribed")); this.pendingSubscribes.delete(room); } - this.transport.send({ - type: "room_message", - payload: { room_id: room, message: { action: "unsubscribe_all" } }, - }); - this.transport.send({ type: "leave_room", payload: { room_id: room } }); this.subscriptions.delete(room); this.rebuildReplay(); + if (this.state === "connected") { + this.transport.sendNow({ + type: "room_message", + payload: { room_id: room, message: { action: "unsubscribe_all" } }, + }); + this.transport.sendNow({ type: "leave_room", payload: { room_id: room } }); + } } private rebuildReplay(): void { this.transport.clearReplayMessages(); for (const [roomId, filters] of this.subscriptions) { - this.transport.addReplayMessage({ type: "join_room", payload: { room_id: roomId } }); - this.transport.addReplayMessage({ - type: "room_message", - payload: { room_id: roomId, message: { action: "subscribe", ...filters } }, - }); + this.transport.addReplayMessages([ + { type: "join_room", payload: { room_id: roomId } }, + { + type: "room_message", + payload: { room_id: roomId, message: { action: "subscribe", ...filters } }, + }, + ]); } } private handleOpen(): void { this.startPing(); + this.restartPendingSubscribes(); this.emit("connected", undefined as never); } private handleClose(code: number, reason: string): void { this.stopPing(); + this.pausePendingSubscribes(); this.emit("disconnected", { code, reason }); } private handleMessage(raw: unknown): void { const msg = raw as { type?: string; room_id?: string; data?: unknown }; if (!msg || typeof msg !== "object" || !msg.type) return; - if (msg.type === "pong") return; + if (msg.type === "pong") { + this.clearPongTimer(); + return; + } if (msg.type === "subscribed" && msg.room_id) { const pending = this.pendingSubscribes.get(msg.room_id as WsRoomId); if (pending) { - clearTimeout(pending.timer); + this.clearSubscribeTimer(pending); this.pendingSubscribes.delete(msg.room_id as WsRoomId); - pending.resolve(msg.data); + const subscribeError = this.getSubscribeError(msg.data); + if (subscribeError) { + const error = new WebSocketError(subscribeError); + pending.reject(error); + this.emit("error", error); + } else { + pending.resolve(msg.data); + } } return; } @@ -201,14 +214,18 @@ export class StructWebSocket { for (const fn of set) { try { (fn as Listener)(payload); - } catch {} + } catch (error) { + this.handleListenerError(error); + } } } private startPing(): void { this.stopPing(); this.pingTimer = setInterval(() => { - this.transport.send({ type: "ping" }); + if (this.transport.sendNow({ type: "ping" })) { + this.armPongTimer(); + } }, PING_INTERVAL_MS); } @@ -217,5 +234,86 @@ export class StructWebSocket { clearInterval(this.pingTimer); this.pingTimer = null; } + this.clearPongTimer(); + } + + private sendSubscription(room: WsRoomId, filters: Record, joinRoom: boolean): boolean { + if (this.state !== "connected") return false; + let sent = true; + if (joinRoom) { + sent = this.transport.sendNow({ type: "join_room", payload: { room_id: room } }) && sent; + } + sent = this.transport.sendNow({ + type: "room_message", + payload: { room_id: room, message: { action: "subscribe", ...filters } }, + }) && sent; + return sent; + } + + private restartPendingSubscribes(): void { + for (const [room, pending] of this.pendingSubscribes) { + if (pending.timer === null) { + this.armSubscribeTimer(room, pending); + } + } + } + + private pausePendingSubscribes(): void { + for (const [, pending] of this.pendingSubscribes) { + this.clearSubscribeTimer(pending); + } + } + + private armSubscribeTimer(room: WsRoomId, pending: PendingSubscribe): void { + this.clearSubscribeTimer(pending); + pending.timer = setTimeout(() => { + pending.timer = null; + this.pendingSubscribes.delete(room); + pending.reject(new WebSocketError(`Subscribe to ${room} timed out`)); + }, this.subscribeTimeout); + } + + private clearSubscribeTimer(pending: PendingSubscribe): void { + if (pending.timer !== null) { + clearTimeout(pending.timer); + pending.timer = null; + } + } + + private armPongTimer(): void { + if (this.pongTimer !== null) return; + this.pongTimer = setTimeout(() => { + this.pongTimer = null; + this.transport.close(4000, "pong timeout"); + }, PING_INTERVAL_MS * 2); + } + + private clearPongTimer(): void { + if (this.pongTimer !== null) { + clearTimeout(this.pongTimer); + this.pongTimer = null; + } + } + + private getSubscribeError(data: unknown): string | null { + if (!data || typeof data !== "object") return null; + const error = (data as { error?: unknown }).error; + return typeof error === "string" && error.length > 0 ? error : null; + } + + private handleListenerError(error: unknown): void { + const normalizedError = error instanceof Error + ? error + : new WebSocketError("WebSocket listener threw", { cause: error }); + if (!this.isEmittingListenerError && (this.listeners.get("error")?.size ?? 0) > 0) { + this.isEmittingListenerError = true; + try { + this.emit("error", normalizedError); + return; + } finally { + this.isEmittingListenerError = false; + } + } + console.error(normalizedError); } } diff --git a/tests/integration.test.ts b/tests/integration.test.ts index 433ce40..87e8406 100644 --- a/tests/integration.test.ts +++ b/tests/integration.test.ts @@ -7,6 +7,7 @@ import { Namespace, PlatformNamespace } from "../src/namespaces/index.js"; import { methodMeta, type MethodConfig } from "./integration.meta.js"; const API_KEY = Bun.env.STRUCT_API_KEY ?? ""; +const RUN_INTEGRATION_TESTS = Bun.env.STRUCT_RUN_INTEGRATION_TESTS === "1"; const REPORT_PATH = "logs/integration-report.md"; type OpenAPISpec = { @@ -354,7 +355,7 @@ function resolveParams(params: Record, setupData: SetupData): R const EXCLUDED_METHODS = new Set(["constructor", "get", "post", "put", "delete"]); -describe.skipIf(!API_KEY)("integration", () => { +describe.skipIf(!API_KEY || !RUN_INTEGRATION_TESTS)("integration", () => { const client = new StructClient({ apiKey: API_KEY, onRequest: (info) => { diff --git a/tests/setup/fake-websocket.ts b/tests/setup/fake-websocket.ts new file mode 100644 index 0000000..b6627ac --- /dev/null +++ b/tests/setup/fake-websocket.ts @@ -0,0 +1,86 @@ +export class FakeWebSocket { + static readonly CONNECTING = 0; + static readonly OPEN = 1; + static readonly CLOSING = 2; + static readonly CLOSED = 3; + + static originalWebSocket: typeof globalThis.WebSocket | undefined; + static readonly instances: FakeWebSocket[] = []; + + readonly url: string; + readyState = FakeWebSocket.CONNECTING; + readonly sent: string[] = []; + onopen: ((event: Event) => void) | null = null; + onclose: ((event: CloseEvent) => void) | null = null; + onerror: ((event: Event) => void) | null = null; + onmessage: ((event: MessageEvent) => void) | null = null; + + constructor(url: string) { + this.url = url; + FakeWebSocket.instances.push(this); + } + + send(data: string): void { + if (this.readyState !== FakeWebSocket.OPEN) { + throw new Error("FakeWebSocket is not open"); + } + this.sent.push(data); + } + + close(code = 1000, reason = ""): void { + if (this.readyState === FakeWebSocket.CLOSED) return; + this.readyState = FakeWebSocket.CLOSING; + this.readyState = FakeWebSocket.CLOSED; + this.onclose?.({ code, reason } as CloseEvent); + } + + open(): void { + if (this.readyState !== FakeWebSocket.CONNECTING) return; + this.readyState = FakeWebSocket.OPEN; + this.onopen?.({ type: "open" } as Event); + } + + serverClose(code = 1006, reason = ""): void { + this.close(code, reason); + } + + serverError(): void { + this.onerror?.({ type: "error" } as Event); + } + + serverSend(data: unknown): void { + this.onmessage?.({ + data: typeof data === "string" ? data : JSON.stringify(data), + } as MessageEvent); + } + + jsonMessages(): Record[] { + return this.sent.map((message) => JSON.parse(message) as Record); + } +} + +export function installFakeWebSocket(): void { + FakeWebSocket.originalWebSocket ??= globalThis.WebSocket; + FakeWebSocket.instances.length = 0; + globalThis.WebSocket = FakeWebSocket as unknown as typeof WebSocket; +} + +export function restoreFakeWebSocket(): void { + if (FakeWebSocket.originalWebSocket) { + globalThis.WebSocket = FakeWebSocket.originalWebSocket; + } + FakeWebSocket.instances.length = 0; +} + +export function latestSocket(): FakeWebSocket { + const socket = FakeWebSocket.instances.at(-1); + if (!socket) { + throw new Error("Expected a FakeWebSocket instance"); + } + return socket; +} + +export async function flushMicrotasks(): Promise { + await Promise.resolve(); + await Promise.resolve(); +} diff --git a/tests/ws-alerts.test.ts b/tests/ws-alerts.test.ts new file mode 100644 index 0000000..6fba809 --- /dev/null +++ b/tests/ws-alerts.test.ts @@ -0,0 +1,166 @@ +import { afterEach, beforeEach, describe, expect, jest, mock, test } from "bun:test"; +import { StructAlertsWebSocket } from "../src/ws-alerts.js"; +import { WebSocketError } from "../src/errors.js"; +import { + flushMicrotasks, + installFakeWebSocket, + latestSocket, + restoreFakeWebSocket, + FakeWebSocket, +} from "./setup/fake-websocket.js"; + +let originalRandom: typeof Math.random; + +beforeEach(() => { + installFakeWebSocket(); + jest.useFakeTimers(); + originalRandom = Math.random; + Math.random = () => 0; +}); + +afterEach(() => { + Math.random = originalRandom; + jest.useRealTimers(); + restoreFakeWebSocket(); +}); + +async function getRejectedError(promise: Promise): Promise { + try { + await promise; + throw new Error("Expected promise to reject"); + } catch (error) { + return error as Error; + } +} + +describe("StructAlertsWebSocket", () => { + test("sends a pre-connect alert subscription only once on first open", async () => { + const ws = new StructAlertsWebSocket({ apiKey: "api-key" }); + const subscribePromise = ws.subscribe("asset_price_tick", {}); + const connectPromise = ws.connect(); + const socket = latestSocket(); + + socket.open(); + await connectPromise; + expect(socket.jsonMessages()).toEqual([{ op: "subscribe", event: "asset_price_tick" }]); + + socket.serverSend({ + op: "subscribed", + event: "asset_price_tick", + subscription_id: "00000000-0000-0000-0000-000000000000", + }); + await expect(subscribePromise).resolves.toEqual({ + op: "subscribed", + event: "asset_price_tick", + subscription_id: "00000000-0000-0000-0000-000000000000", + }); + }); + + test("pauses alert subscribe timeouts during reconnect", async () => { + const ws = new StructAlertsWebSocket({ + apiKey: "api-key", + subscribeTimeout: 100, + reconnect: { maxRetries: 1, initialDelayMs: 10, maxDelayMs: 10 }, + }); + + const connectPromise = ws.connect(); + const firstSocket = latestSocket(); + firstSocket.open(); + await connectPromise; + + const subscribePromise = ws.subscribe("asset_price_tick", {}); + firstSocket.serverClose(1006, "offline"); + + jest.advanceTimersByTime(10); + const secondSocket = latestSocket(); + let rejected: Error | undefined; + subscribePromise.catch((error) => { + rejected = error as Error; + }); + + jest.advanceTimersByTime(200); + await flushMicrotasks(); + expect(rejected).toBeUndefined(); + + secondSocket.open(); + await flushMicrotasks(); + expect(secondSocket.jsonMessages()).toEqual([{ op: "subscribe", event: "asset_price_tick" }]); + + secondSocket.serverSend({ + op: "subscribed", + event: "asset_price_tick", + subscription_id: "00000000-0000-0000-0000-000000000000", + }); + await expect(subscribePromise).resolves.toEqual({ + op: "subscribed", + event: "asset_price_tick", + subscription_id: "00000000-0000-0000-0000-000000000000", + }); + }); + + test("rejects pending alert subscriptions immediately on error frames", async () => { + const ws = new StructAlertsWebSocket({ apiKey: "api-key" }); + const errors: Error[] = []; + ws.on("error", (error) => { + errors.push(error); + }); + + const connectPromise = ws.connect(); + const socket = latestSocket(); + socket.open(); + await connectPromise; + + const subscribePromise = ws.subscribe("asset_price_tick", {}); + socket.serverSend({ + event: "asset_price_tick", + error: "invalid alert filter", + }); + + const error = await getRejectedError(subscribePromise); + expect(error).toBeInstanceOf(WebSocketError); + expect(error.message).toContain("invalid alert filter"); + expect(errors).toHaveLength(1); + }); + + test("sends type-based pings and reconnects when pong is missing", async () => { + const ws = new StructAlertsWebSocket({ + apiKey: "api-key", + reconnect: { maxRetries: 1, initialDelayMs: 10, maxDelayMs: 10 }, + }); + const onReconnecting = mock((_payload: { attempt: number }) => {}); + ws.on("reconnecting", onReconnecting); + + const connectPromise = ws.connect(); + const firstSocket = latestSocket(); + firstSocket.open(); + await connectPromise; + + jest.advanceTimersByTime(30_000); + expect(firstSocket.jsonMessages().at(-1)).toEqual({ type: "ping" }); + + jest.advanceTimersByTime(60_000); + await flushMicrotasks(); + expect(onReconnecting).toHaveBeenCalledTimes(1); + expect(firstSocket.readyState).toBe(FakeWebSocket.CLOSED); + + jest.advanceTimersByTime(10); + expect(FakeWebSocket.instances).toHaveLength(2); + }); + + test("surfaces listener exceptions through the error event", async () => { + const ws = new StructAlertsWebSocket({ apiKey: "api-key" }); + const onError = mock((_error: Error) => {}); + + ws.on("error", onError); + ws.on("connected", () => { + throw new Error("alerts listener exploded"); + }); + + const connectPromise = ws.connect(); + latestSocket().open(); + await connectPromise; + + expect(onError).toHaveBeenCalledTimes(1); + expect((onError.mock.calls[0]![0] as Error).message).toBe("alerts listener exploded"); + }); +}); diff --git a/tests/ws-transport.test.ts b/tests/ws-transport.test.ts new file mode 100644 index 0000000..bc950ef --- /dev/null +++ b/tests/ws-transport.test.ts @@ -0,0 +1,178 @@ +import { afterEach, beforeEach, describe, expect, jest, mock, test } from "bun:test"; +import { WebSocketClosedError } from "../src/errors.js"; +import { WebSocketTransport, buildWebSocketUrl } from "../src/ws-transport.js"; +import { + flushMicrotasks, + installFakeWebSocket, + latestSocket, + restoreFakeWebSocket, + FakeWebSocket, +} from "./setup/fake-websocket.js"; + +let originalRandom: typeof Math.random; + +beforeEach(() => { + installFakeWebSocket(); + jest.useFakeTimers(); + originalRandom = Math.random; + Math.random = () => 0; +}); + +afterEach(() => { + Math.random = originalRandom; + jest.useRealTimers(); + restoreFakeWebSocket(); +}); + +function createCallbacks() { + return { + onOpen: mock(() => {}), + onClose: mock((_code: number, _reason: string) => {}), + onError: mock((_error: Error) => {}), + onMessage: mock((_data: unknown) => {}), + onReconnecting: mock((_attempt: number) => {}), + onReconnectFailed: mock((_error: Error) => {}), + onAuthFailed: mock((_error: WebSocketClosedError) => {}), + onWarning: mock((_warning: Error) => {}), + }; +} + +async function getRejectedError(promise: Promise): Promise { + try { + await promise; + throw new Error("Expected promise to reject"); + } catch (error) { + return error as Error; + } +} + +describe("WebSocketTransport", () => { + test("rebuilds the websocket URL on reconnect and resolves connect after a retry", async () => { + let jwt = "jwt-1"; + const callbacks = createCallbacks(); + const transport = new WebSocketTransport( + () => buildWebSocketUrl("/ws", { apiKey: "api-key", jwt }, "https://api.struct.to"), + { maxRetries: 2, initialDelayMs: 10, maxDelayMs: 10 }, + callbacks, + ); + + const connectPromise = transport.connect(); + const firstSocket = latestSocket(); + expect(firstSocket.url).toContain("token=jwt-1"); + + firstSocket.serverClose(1006, "offline"); + await flushMicrotasks(); + expect(callbacks.onReconnecting).toHaveBeenCalledTimes(1); + + jwt = "jwt-2"; + jest.advanceTimersByTime(10); + const secondSocket = latestSocket(); + expect(secondSocket).not.toBe(firstSocket); + expect(secondSocket.url).toContain("token=jwt-2"); + + secondSocket.open(); + await connectPromise; + expect(transport.state).toBe("connected"); + }); + + test("emits reconnect_failed and rejects connect after retries are exhausted", async () => { + const callbacks = createCallbacks(); + const transport = new WebSocketTransport( + "wss://api.struct.to/ws", + { maxRetries: 1, initialDelayMs: 10, maxDelayMs: 10 }, + callbacks, + ); + + const connectPromise = transport.connect(); + latestSocket().serverClose(1006, "offline"); + jest.advanceTimersByTime(10); + latestSocket().serverClose(1006, "still offline"); + + const error = await getRejectedError(connectPromise); + expect(error).toBeInstanceOf(WebSocketClosedError); + expect(callbacks.onReconnectFailed).toHaveBeenCalledTimes(1); + expect(callbacks.onAuthFailed).not.toHaveBeenCalled(); + expect(transport.state).toBe("disconnected"); + }); + + test("rejects pending connect and cancels retry when disconnected during reconnect", async () => { + const callbacks = createCallbacks(); + const transport = new WebSocketTransport( + "wss://api.struct.to/ws", + { maxRetries: 2, initialDelayMs: 10, maxDelayMs: 10 }, + callbacks, + ); + + const connectPromise = transport.connect(); + latestSocket().serverClose(1006, "offline"); + transport.disconnect(); + + const error = await getRejectedError(connectPromise); + expect(error).toBeInstanceOf(WebSocketClosedError); + + jest.advanceTimersByTime(20); + expect(FakeWebSocket.instances).toHaveLength(1); + expect(transport.state).toBe("disconnected"); + }); + + test("caps the pending queue and drops the oldest message", async () => { + const callbacks = createCallbacks(); + const transport = new WebSocketTransport( + "wss://api.struct.to/ws", + { maxPendingMessages: 2 }, + callbacks, + ); + + transport.send({ id: 1 }); + transport.send({ id: 2 }); + transport.send({ id: 3 }); + + expect(callbacks.onWarning).toHaveBeenCalledTimes(1); + + const connectPromise = transport.connect(); + const socket = latestSocket(); + socket.open(); + await connectPromise; + + expect(socket.jsonMessages()).toEqual([{ id: 2 }, { id: 3 }]); + }); + + test("caps the replay queue by replay entry so grouped replays stay intact", async () => { + const callbacks = createCallbacks(); + const transport = new WebSocketTransport( + "wss://api.struct.to/ws", + { maxPendingMessages: 1 }, + callbacks, + ); + + transport.addReplayMessages([{ id: "join-1" }, { id: "subscribe-1" }]); + transport.addReplayMessages([{ id: "join-2" }, { id: "subscribe-2" }]); + + expect(callbacks.onWarning).toHaveBeenCalledTimes(1); + + const connectPromise = transport.connect(); + const socket = latestSocket(); + socket.open(); + await connectPromise; + + expect(socket.jsonMessages()).toEqual([{ id: "join-2" }, { id: "subscribe-2" }]); + }); + + test("treats auth close codes as terminal failures", async () => { + const callbacks = createCallbacks(); + const transport = new WebSocketTransport( + "wss://api.struct.to/ws", + { maxRetries: 3, initialDelayMs: 10, maxDelayMs: 10 }, + callbacks, + ); + + const connectPromise = transport.connect(); + latestSocket().serverClose(1008, "token expired"); + + const error = await getRejectedError(connectPromise); + expect(error).toBeInstanceOf(WebSocketClosedError); + expect(callbacks.onAuthFailed).toHaveBeenCalledTimes(1); + expect(callbacks.onReconnecting).not.toHaveBeenCalled(); + expect(transport.state).toBe("disconnected"); + }); +}); diff --git a/tests/ws.test.ts b/tests/ws.test.ts new file mode 100644 index 0000000..8619103 --- /dev/null +++ b/tests/ws.test.ts @@ -0,0 +1,244 @@ +import { afterEach, beforeEach, describe, expect, jest, mock, test } from "bun:test"; +import { StructWebSocket } from "../src/ws.js"; +import { WebSocketError } from "../src/errors.js"; +import { + flushMicrotasks, + installFakeWebSocket, + latestSocket, + restoreFakeWebSocket, + FakeWebSocket, +} from "./setup/fake-websocket.js"; + +let originalRandom: typeof Math.random; + +beforeEach(() => { + installFakeWebSocket(); + jest.useFakeTimers(); + originalRandom = Math.random; + Math.random = () => 0; +}); + +afterEach(() => { + Math.random = originalRandom; + jest.useRealTimers(); + restoreFakeWebSocket(); +}); + +async function getRejectedError(promise: Promise): Promise { + try { + await promise; + throw new Error("Expected promise to reject"); + } catch (error) { + return error as Error; + } +} + +describe("StructWebSocket", () => { + test("sends a pre-connect subscription only once on first open", async () => { + const ws = new StructWebSocket({ apiKey: "api-key" }); + const subscribePromise = ws.subscribe("polymarket_trades"); + const connectPromise = ws.connect(); + const socket = latestSocket(); + + socket.open(); + await connectPromise; + expect(socket.jsonMessages()).toEqual([ + { type: "join_room", payload: { room_id: "polymarket_trades" } }, + { + type: "room_message", + payload: { + room_id: "polymarket_trades", + message: { action: "subscribe" }, + }, + }, + ]); + + socket.serverSend({ + type: "subscribed", + room_id: "polymarket_trades", + data: { subscribe_all: true }, + }); + await expect(subscribePromise).resolves.toEqual({ subscribe_all: true }); + }); + + test("keeps room replays intact when the replay queue is capped", async () => { + const ws = new StructWebSocket({ + apiKey: "api-key", + reconnect: { maxPendingMessages: 1 }, + }); + const warnings: Error[] = []; + ws.on("warning", (warning) => { + warnings.push(warning); + }); + + const subscribePromise = ws.subscribe("polymarket_trades"); + const connectPromise = ws.connect(); + const socket = latestSocket(); + + socket.open(); + await connectPromise; + expect(socket.jsonMessages()).toEqual([ + { type: "join_room", payload: { room_id: "polymarket_trades" } }, + { + type: "room_message", + payload: { + room_id: "polymarket_trades", + message: { action: "subscribe" }, + }, + }, + ]); + expect(warnings).toEqual([]); + + socket.serverSend({ + type: "subscribed", + room_id: "polymarket_trades", + data: { subscribe_all: true }, + }); + await expect(subscribePromise).resolves.toEqual({ subscribe_all: true }); + }); + + test("pauses subscribe timeout during reconnect and resolves after replayed ack", async () => { + const ws = new StructWebSocket({ + apiKey: "api-key", + subscribeTimeout: 100, + reconnect: { maxRetries: 1, initialDelayMs: 10, maxDelayMs: 10 }, + }); + + const connectPromise = ws.connect(); + const firstSocket = latestSocket(); + firstSocket.open(); + await connectPromise; + + const subscribePromise = ws.subscribe("polymarket_trades"); + firstSocket.serverClose(1006, "offline"); + + jest.advanceTimersByTime(10); + const secondSocket = latestSocket(); + let rejected: Error | undefined; + subscribePromise.catch((error) => { + rejected = error as Error; + }); + + jest.advanceTimersByTime(200); + await flushMicrotasks(); + expect(rejected).toBeUndefined(); + + secondSocket.open(); + await flushMicrotasks(); + expect(secondSocket.jsonMessages()).toEqual([ + { type: "join_room", payload: { room_id: "polymarket_trades" } }, + { + type: "room_message", + payload: { + room_id: "polymarket_trades", + message: { action: "subscribe" }, + }, + }, + ]); + + secondSocket.serverSend({ + type: "subscribed", + room_id: "polymarket_trades", + data: { subscribe_all: true }, + }); + await expect(subscribePromise).resolves.toEqual({ subscribe_all: true }); + }); + + test("does not queue stale unsubscribe messages while reconnecting", async () => { + const ws = new StructWebSocket({ + apiKey: "api-key", + reconnect: { maxRetries: 1, initialDelayMs: 10, maxDelayMs: 10 }, + }); + + const connectPromise = ws.connect(); + const firstSocket = latestSocket(); + firstSocket.open(); + await connectPromise; + + const subscribePromise = ws.subscribe("polymarket_trades"); + firstSocket.serverSend({ + type: "subscribed", + room_id: "polymarket_trades", + data: { subscribe_all: true }, + }); + await subscribePromise; + + firstSocket.serverClose(1006, "offline"); + ws.unsubscribe("polymarket_trades"); + + jest.advanceTimersByTime(10); + const secondSocket = latestSocket(); + secondSocket.open(); + await flushMicrotasks(); + + expect(secondSocket.jsonMessages()).toEqual([]); + }); + + test("rejects subscribe promises immediately when the ack contains an error", async () => { + const ws = new StructWebSocket({ apiKey: "api-key" }); + const errors: Error[] = []; + ws.on("error", (error) => { + errors.push(error); + }); + + const connectPromise = ws.connect(); + const socket = latestSocket(); + socket.open(); + await connectPromise; + + const subscribePromise = ws.subscribe("polymarket_trades"); + socket.serverSend({ + type: "subscribed", + room_id: "polymarket_trades", + data: { error: "bad filters" }, + }); + + const error = await getRejectedError(subscribePromise); + expect(error).toBeInstanceOf(WebSocketError); + expect(error.message).toContain("bad filters"); + expect(errors).toHaveLength(1); + expect(errors[0]?.message).toContain("bad filters"); + }); + + test("surfaces listener exceptions through the error event", async () => { + const ws = new StructWebSocket({ apiKey: "api-key" }); + const onError = mock((_error: Error) => {}); + + ws.on("error", onError); + ws.on("connected", () => { + throw new Error("listener exploded"); + }); + + const connectPromise = ws.connect(); + latestSocket().open(); + await connectPromise; + + expect(onError).toHaveBeenCalledTimes(1); + expect((onError.mock.calls[0]![0] as Error).message).toBe("listener exploded"); + }); + + test("closes and reconnects when pong is missing", async () => { + const ws = new StructWebSocket({ + apiKey: "api-key", + reconnect: { maxRetries: 1, initialDelayMs: 10, maxDelayMs: 10 }, + }); + const onReconnecting = mock((_payload: { attempt: number }) => {}); + ws.on("reconnecting", onReconnecting); + + const connectPromise = ws.connect(); + const firstSocket = latestSocket(); + firstSocket.open(); + await connectPromise; + + jest.advanceTimersByTime(30_000); + expect(firstSocket.jsonMessages().at(-1)).toEqual({ type: "ping" }); + + jest.advanceTimersByTime(60_000); + await flushMicrotasks(); + expect(onReconnecting).toHaveBeenCalledTimes(1); + expect(firstSocket.readyState).toBe(FakeWebSocket.CLOSED); + + jest.advanceTimersByTime(10); + expect(FakeWebSocket.instances).toHaveLength(2); + }); +}); From 7299e32cf2d1d5a106c3d8610ad0e31e512819ae Mon Sep 17 00:00:00 2001 From: elliotdotsol Date: Sun, 12 Apr 2026 01:36:33 +0700 Subject: [PATCH 12/12] fix: Polynomial regular expression used on uncontrolled data --- src/ws-transport.ts | 22 ++++++++++++++++++++-- tests/ws-transport.test.ts | 14 ++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/ws-transport.ts b/src/ws-transport.ts index 9cd1954..682846d 100644 --- a/src/ws-transport.ts +++ b/src/ws-transport.ts @@ -25,13 +25,31 @@ export function buildWebSocketUrl( config: { apiKey: string; jwt?: string; baseUrl?: string }, defaultBaseUrl: string, ): string { - const base = (config.baseUrl ?? defaultBaseUrl).replace(/\/+$/, ""); - const wsBase = base.replace(/^https:\/\//, "wss://").replace(/^http:\/\//, "ws://"); + const base = trimTrailingSlashes(config.baseUrl ?? defaultBaseUrl); + const wsBase = toWebSocketBaseUrl(base); const params = new URLSearchParams({ "api-key": config.apiKey }); if (config.jwt) params.set("token", config.jwt); return `${wsBase}${path}?${params.toString()}`; } +function trimTrailingSlashes(value: string): string { + let end = value.length; + while (end > 0 && value.charCodeAt(end - 1) === 47) { + end--; + } + return end === value.length ? value : value.slice(0, end); +} + +function toWebSocketBaseUrl(baseUrl: string): string { + if (baseUrl.startsWith("https://")) { + return `wss://${baseUrl.slice("https://".length)}`; + } + if (baseUrl.startsWith("http://")) { + return `ws://${baseUrl.slice("http://".length)}`; + } + return baseUrl; +} + export interface WebSocketTransportCallbacks { onOpen: () => void; onClose: (code: number, reason: string) => void; diff --git a/tests/ws-transport.test.ts b/tests/ws-transport.test.ts index bc950ef..3f8fdc3 100644 --- a/tests/ws-transport.test.ts +++ b/tests/ws-transport.test.ts @@ -47,6 +47,20 @@ async function getRejectedError(promise: Promise): Promise { } describe("WebSocketTransport", () => { + test("buildWebSocketUrl normalizes trailing slashes and websocket protocol", () => { + expect( + buildWebSocketUrl("/ws", { apiKey: "api-key", baseUrl: "https://api.struct.to///" }, "http://ignored"), + ).toBe("wss://api.struct.to/ws?api-key=api-key"); + + expect( + buildWebSocketUrl("/ws", { apiKey: "api-key", baseUrl: "http://localhost:3000/" }, "https://ignored"), + ).toBe("ws://localhost:3000/ws?api-key=api-key"); + + expect( + buildWebSocketUrl("/ws", { apiKey: "api-key", baseUrl: "wss://stream.struct.to/" }, "https://ignored"), + ).toBe("wss://stream.struct.to/ws?api-key=api-key"); + }); + test("rebuilds the websocket URL on reconnect and resolves connect after a retry", async () => { let jwt = "jwt-1"; const callbacks = createCallbacks();