TL;DR
Polymarket is migrating from V1 contracts (USDC.e collateral) to V2 contracts (pUSD collateral). The WebSocket service now handles both - V1 and V2 events flow through the same channels and subscription semantics. Additive changes:- New
versionfield onorder_filled, activity, and lifecycle events (1or2) - New
builderandmetadatafields on V2order_filledevents - New
collateralchannel for pUSD deposit/withdrawal events - New
condition_preparedevent type on the lifecycle channel (with derived token IDs for binary markets) - New
conversionevent type on the activity channel (NegRisk cross-condition conversions)
ActivityAlert.condition_idis now nullable -nullonly for the newconversionevent type. Clients with typed schemas (condition_id: string) should widen tostring | nullif they want to consume conversion events. Clients that filter byevent_typein{"split", "merge", "redeem"}are unaffected.- Pending-tx access is now Dev+ gated - Free-tier clients passing
filters.status: "all"or"pending"receivePLAN_REQUIRED. Free-tier clients on the default ("confirmed") continue to work unchanged.
Breaking Change: token_registered Only Fires for V1
The
condition_prepared event fires earlier than token_registered. For binary markets (most Polymarket markets), the service derives token IDs deterministically from condition_id + is_neg_risk and includes them in the tokens array - no extra API call needed. Token labels are placeholders ("Yes" / "No"); resolve canonical labels from Gamma/CLOB if needed. Non-binary markets have tokens: null.
New Fields on Existing Events
Trade events (order_filled)
V1 fills are byte-identical to pre-migration plus a single new version field:
builder and metadata (bytes32 hex, zero until Polymarket populates them):
- No
fee_refundevents on V2 - V2 has no refund flow. The net fee is emitted directly onorder_filledat match time. - V2 uses separate taker and per-maker fee amounts. In practice makers typically see
fee: 0today (operators haven’t populated maker fees), but the protocol supports non-zero maker fees viamakerFeeAmounts[]. - V1
fee_refundbehavior is unchanged.
Lifecycle events
Now carry aversion field (1 or 2) indicating which contracts emitted them. All other fields unchanged.
Activity events
Now carry aversion field (1 for split/merge/redeem, 2 for the new conversion event type).
New Activity Event: conversion
NegRisk cross-condition conversions (user converts “No” positions back to collateral across a NegRisk event).
condition_idis alwaysnull(conversion spans multiple conditions).neg_risk_event_id: NegRiskAdapter’s marketId identifying the cluster of related binary questions.index_set:uint256bitmap (as decimal string) of which question indices were converted.- See Activity Events for full details.
New Channel: collateral
V2 replaces USDC.e with pUSD as the trading collateral. When users deposit/withdraw, the pUSD contract emits Wrapped / Unwrapped events. These flow through a new opt-in collateral channel.
Subscribe:
users filter or wildcard. Does not accept condition_ids, market_slugs, or token_ids - collateral flow isn’t tied to a market.
Event shape:
event_type:"polyusd_wrapped"(deposit: underlying → pUSD) or"polyusd_unwrapped"(withdrawal: pUSD → underlying)user: end-recipient of the operationasset: underlying ERC-20 address (typically USDC.e)amount/amount_normalized: 6-decimal (same as USDC)
Activity events (splits, merges, redeems) are not mixed into the collateral channel. Subscribe to both if you need full wallet flow.
Accepted Channel Types
Contract Addresses
Backwards-Compatibility Guarantees
- No field removed, no field renamed, no filter semantic changed.
- V1 clients that don’t parse
version,builder, ormetadatawill ignore them - same JSON shape as before plus extra keys. - Clients with strict JSON schemas that reject unknown properties need a one-line schema update (allow additional properties, or add the new optional fields).
- Clients with a closed enum for
event_typeshould add"condition_prepared","polyusd_wrapped","polyusd_unwrapped"if they want to surface those.
Recommended Migration Steps
1
Update your event handlers (optional)
Read the new
version field on trade/activity/lifecycle events if you want to branch on V1 vs V2 behavior.2
Fix token discovery (required if you relied on token_registered)
If you used
token_registered as your “new market” signal, add a handler for condition_prepared. Query Gamma or CLOB by condition_id to resolve token IDs.3
Subscribe to collateral (optional)
If you track wallet deposit/withdrawal flow, subscribe to the new
collateral channel with type: "collateral".4
Relax strict schema validation (if applicable)
If your JSON parser rejects unknown keys, add
version, builder, metadata as optional fields - or allow additional properties.