Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.struct.to/llms.txt

Use this file to discover all available pages before exploring further.

The Polymarket CLOB pays maker rewards on a curated set of markets. Each rewarded market carries one or more reward configs (clob_rewards[]), each with a daily rate, a max spread, and a min order size. Struct exposes these through the markets list (filter has_rewards=true, sort sort_by=rewards) and via the markets stream and CLOB rewards rooms for live updates.

When to use this

  • Market-maker tooling: a leaderboard of “where can I earn the most rebates today?”
  • Reward eligibility checks: filter to markets with rewards_max_spread your strategy can hit.
  • Sponsor monitoring: track new sponsors joining or rates changing on a watched market.

Step 1: list reward-bearing markets

has_rewards=true keeps only markets with at least one active reward config; sort_by=rewards orders the response by combined daily rate descending.
import { StructClient } from "@structbuild/sdk";

const client = new StructClient({ apiKey: "sk_live_xxx" });

const { data: markets } = await client.markets.getMarkets({
  has_rewards: true,
  sort_by: "rewards",
  limit: 50,
});

Step 2: read the reward fields

Each market row carries a top-level total_daily_rate (the combined daily rate across all sponsors on that market) and a clob_rewards[] array with the per-config breakdown:
FieldTypeDescription
total_daily_ratenumber | nullTop-level: combined daily rate across sponsors.
clob_rewards[].rewards_daily_ratenumber | nullDaily rate for this config.
clob_rewards[].native_daily_ratenumber | nullPolymarket native rate.
clob_rewards[].sponsored_daily_ratenumber | nullSponsor-funded rate.
clob_rewards[].rewards_max_spreadnumber | nullMax eligible spread (probability units).
clob_rewards[].rewards_min_sizenumber | nullMin eligible order size (USD).
clob_rewards[].start_datestring | nullISO date the reward starts.
clob_rewards[].end_datestring | nullISO date the reward ends.
clob_rewards[].sponsors_countinteger | nullActive sponsor count.
The combined total_daily_rate is the right number for the dashboard’s primary sort. The per-config breakdown is what you show on the row’s expanded view.

Step 3: keep the dashboard fresh

Two paths, depending on freshness needs:

Coarse: re-poll on an interval

setInterval(async () => {
  const { data } = await client.markets.getMarkets({ has_rewards: true, sort_by: "rewards", limit: 50 });
  renderDashboard(data);
}, 60_000);

Live: subscribe to the markets stream

polymarket_markets_stream accepts the same has_rewards filter and pushes full market rows whenever they change.
import { StructWebSocket } from "@structbuild/sdk";

const ws = new StructWebSocket({ apiKey: "sk_live_xxx" });
await ws.connect();

await ws.subscribe("polymarket_markets_stream", {
  interval_ms: 1000,
  mode: "filter",
  filter: { has_rewards: true },
});

const byCondition = new Map<string, MarketResponse>();
for (const row of markets) byCondition.set(row.condition_id, row);

ws.on("markets_stream_update", (event) => {
  for (const row of event.data) byCondition.set(row.condition_id, row);
  const sorted = [...byCondition.values()].sort(
    (a, b) => (b.total_daily_rate ?? 0) - (a.total_daily_rate ?? 0),
  );
  renderDashboard(sorted);
});
The stream only pushes rows that actually changed since the last flush, so re-sorting by total_daily_rate runs in bounded time per tick.

Step 4: stream raw reward config changes

For sponsor-level events (a new sponsor joining a market, a rate change, an end date hit) subscribe to polymarket_clob_rewards. Each clob_rewards_update carries the full reward config so you can merge into a per-market reward map.
await ws.subscribe("polymarket_clob_rewards", {
  condition_ids: ["0xabc123..."],
});

ws.on("clob_rewards_update", (event) => {
  upsertRewardConfig(event.condition_id, event.reward);
});
See CLOB Rewards for the full config shape.

Common combinations

GoalParameters
Top reward markets right nowhas_rewards=true&sort_by=rewards&limit=50
High-liquidity rewarded markets onlyhas_rewards=true&min_liquidity=50000&sort_by=rewards
Crypto rewards onlyhas_rewards=true&categories=crypto&sort_by=rewards
High-volume rewarded marketshas_rewards=true&min_volume=100000&timeframe=24h
Track specific marketspolymarket_markets_stream with mode=ids and condition_ids=[...]

Follow-on

To check whether your own quotes are inside the reward band on the markets you maker on, subscribe to polymarket_order_book for the same condition_ids. Compare the live spread to each market’s rewards_max_spread and flag rows where you’re out of band.
Last modified on April 28, 2026