Skip to main content
PolyNode streams Polymarket combo activity from on-chain combo transactions. The stream follows the same lifecycle as standard settlements: pending events come from mempool calldata, then confirmation events come from on-chain receipts.
This is the on-chain combo stream. Polymarket’s RFQ gateway is an off-chain maker/quoter channel. Use this stream to monitor combo executions, fills, confirmations, and enriched lifecycle actions as they hit Polygon.

Subscribe

{
  "action": "subscribe",
  "type": "combos"
}
The default combos preset emits:
EventTimingPurpose
combo_executionPending / mempoolCombo order execution decoded before confirmation.
combo_status_updateConfirmed / receiptConfirmation, exact receipt fills, fees, transfers, and latency.
Every customer-facing combo event is enrichment-gated. If a combo leg cannot be resolved to market metadata, the event is held rather than emitted partially.

Full combo surface

Advanced users can explicitly request lifecycle and approval events:
{
  "action": "subscribe",
  "type": "combos",
  "filters": {
    "event_types": [
      "combo_execution",
      "combo_status_update",
      "combo_lifecycle",
      "combo_approval"
    ]
  }
}
Lifecycle events are emitted only when their legs are present and enriched. Condition-only lifecycle actions are not emitted unless they can be represented without requiring a follow-up lookup.

Covered on-chain surface

The combo stream covers the Polymarket on-chain contracts used for combo execution and position lifecycle activity:
ContractAddressSurface
ExchangeV30xe3333700cA9d93003F00f0F71f8515005F6c00AaCombo order execution and confirmation.
PositionManager0x006F54F7f9A22e0000CC2AB60031000000ae9fEFPosition transfers and approvals.
BinaryModule0x1000008dD9001B968442c1000017eaE6E0dA00BaSplit, merge, redeem, migration, and result lifecycle calls.
NegRiskModule0x200000900045e3B6259600682756002200028933Negative-risk split, merge, redeem, convert, migration, and result calls.
CombinatorialModule0x30000034706C7d8e12009DAB006Be20000c031A8Prepare, split, merge, extract, inject, wrap, unwrap, compress, redeem, and basket conversion.
Router0x12121212006e4CD160D18e3f00711DA5c3372600Router split, merge, redeem, horizontal split/merge, and convert.
AutoRedeemer0xa1200000d0002264C9a1698e001292D00E1b00afAuto redeem calls and confirmations.
PositionManager approvals for ExchangeV3 and AutoRedeemer are available through combo_approval when requested explicitly. Collateral ERC20 allowance approvals are not part of the default combo stream.

Example

import WebSocket from "ws";

const ws = new WebSocket("wss://ws.polynode.dev/ws?key=pn_live_YOUR_KEY");
const pending = new Map();

ws.on("open", () => {
  ws.send(JSON.stringify({ action: "subscribe", type: "combos" }));
});

ws.on("message", (raw) => {
  const msg = JSON.parse(raw);

  if (msg.type === "combo_execution") {
    pending.set(msg.data.tx_hash, msg.data);
    console.log("pending combo", msg.data.tx_hash, msg.data.legs.length, "legs");
  }

  if (msg.type === "combo_status_update") {
    const original = pending.get(msg.data.tx_hash);
    console.log("confirmed combo", msg.data.tx_hash, {
      latency_ms: msg.data.latency_ms,
      pending_seen: Boolean(original),
      fills: msg.data.confirmed_fills?.length ?? 0
    });
  }
});

Filters

Combo subscriptions support the standard WebSocket filters plus combo-specific identifiers:
{
  "action": "subscribe",
  "type": "combos",
  "filters": {
    "wallets": ["0xMakerOrTaker..."],
    "leg_position_ids": ["123456789..."],
    "tokens": ["123456789..."],
    "combo_condition_ids": ["0xcombo..."],
    "condition_ids": ["0xleg_or_combo_condition..."],
    "event_ids": ["0xevent..."],
    "module_ids": [3],
    "side": "YES",
    "direction": "BUY",
    "status": "confirmed",
    "min_size": 100
  }
}
tokens and leg_position_ids both match combo position IDs and leg position IDs. Use leg_position_ids when you want the filter to be self-documenting.

Event reference