Skip to main content
In this recipe we’ll walk through building a prediction event detail page, the kind of page Polymarket and Kalshi center their UX around. An event like “2024 Presidential Election” contains multiple related markets (“Who wins?”, “Popular vote margin?”, “Which states flip?”). We’ll combine multiple Codex endpoints to populate every section: event metadata, market probabilities, multi-market charts, aggregated activity, trade history, and market drill-downs.

Step 1: Event Metadata & Market List

For the examples below to work, you’ll need an ID of an event. You can get that by using filterPredictionEvents. Take the ouput of that and replace the eventId value in the queries below.Unforunately, Prediction Markets are ever changing so it’s hard for us to hardcode an example like we can with tokens.
Start by fetching the event details and all its markets in a single call with detailedPredictionEventStats. This returns event metadata, the full list of markets, aggregated stats across time windows, and lifecycle information.
Test this query in the Explorer →
query DetailedPredictionEventStats {
  detailedPredictionEventStats(input: { eventId: "yourEventId" }) {
    eventId
    lastTransactionAt
    predictionEvent {
      id
      protocol
      venueEventId
      status
      question
      url
      rulesPrimary
      rulesSecondary
      tags
      opensAt
      closesAt
      resolvesAt
      resolvedAt
      resolution {
        result
        source
      }
      imageLargeUrl
      imageThumbUrl
      createdAt
      updatedAt
      networkId
      marketIds
      categories {
        name
        slug
        subcategories {
          name
          slug
        }
      }
    }
    predictionMarkets {
      id
      protocol
      venueMarketId
      eventId
      question
      label
      eventLabel
      outcomeLabels
      outcomeIds
      resolution {
        result
        source
      }
      imageThumbUrl
      createdAt
      opensAt
      closesAt
      resolvesAt
      resolvedAt
      networkId
    }
    statsDay1 {
      start
      end
      statsCurrency {
        volumeUsd
        volumeCT
        openLiquidityUsd
        closeLiquidityUsd
        openOpenInterestUsd
        closeOpenInterestUsd
      }
      statsNonCurrency {
        trades
        uniqueTraders
      }
      statsChange {
        volumeChange
        openLiquidityChange
        openOpenInterestChange
        tradesChange
        uniqueTradersChange
      }
      scores {
        trending
        relevance
      }
    }
    allTimeStats {
      volumeUsd
      volumeCT
      venueVolumeUsd
      venueVolumeCT
    }
    lifecycle {
      ageSeconds
      expectedLifespanSeconds
      timeToResolutionSeconds
      isResolved
    }
  }
}
This is the core call that populates the event header, market list sidebar, and summary stats. It gives you everything you need to render the top of the page in one request. Stats are available at multiple windows. statsDay1 is shown above, but statsHour1, statsHour4, statsHour12, statsWeek1 follow the same structure.

Step 2: Market Outcome Pricing

To show current probabilities (best ask price) for each market’s outcomes (the core of any prediction market UI), use filterPredictionMarkets scoped to the event. This returns real-time bid/ask pricing, spread, liquidity depth, and volume for each outcome.
Test this query in the Explorer →
query EventMarketPricing {
  filterPredictionMarkets(
    eventIds: ["yourEventId"]
    rankings: [
      { outcome: outcome0, outcomeAttribute: bestAskCT, direction: DESC }
    ]
  ) {
    count
    results {
      id
      status
      market {
        id
        label
        question
        imageThumbUrl
      }
      outcome0 {
        label
        bestAskCT
        bestBidCT
        spreadCT
        lastPriceCT
        liquidityCT
        volumeUsd24h
        priceChange24h
      }
      outcome1 {
        label
        bestAskCT
        bestBidCT
        spreadCT
        lastPriceCT
        liquidityCT
        volumeUsd24h
        priceChange24h
      }
      volumeUsdAll
      liquidityUsd
      openInterestUsd
    }
  }
}
  • The bestAskCT price (in collateral token, e.g., USDC) represents the current implied probability (0.65 = 65% chance)
  • Ranking by outcome0’s bestAskCT in DESC order puts the highest-probability outcomes at the top
  • You can also rank by market-level attributes like volumeUsd24h or trendingScore24h
  • The spread (bestAskCT - bestBidCT) indicates market efficiency
  • This is the data that powers the market list showing “Yes 65¢ / No 35¢” for each market

Step 3: Multi-Market Probability Chart

The signature visualization: a multi-line chart showing how probabilities for the top markets in an event have moved over time. Use predictionEventTopMarketsBars.
Test this query in the Explorer →
query EventTopMarketsBars {
  predictionEventTopMarketsBars(
    input: {
      eventId: "yourEventId"
      from: 1773100000
      to: 1773700000
      resolution: hour1
      limit: 5
      rankBy: "volumeUsd1w"
      rankDirection: "DESC"
    }
  ) {
    eventId
    predictionEvent {
      id
      question
    }
    marketBars {
      marketId
      predictionMarket {
        id
        label
        outcomeLabels
      }
      bars {
        t
        outcome0 {
          priceCollateralToken {
            o
            h
            l
            c
          }
          volumeUsd
          trades
        }
        outcome1 {
          priceCollateralToken {
            o
            h
            l
            c
          }
        }
        openInterestUsd {
          o
          h
          l
          c
        }
      }
    }
  }
}
  • Returns OHLC bars for the top N markets (up to 10) in a single request
  • rankBy determines which markets are “top”. Use volumeUsd1w for most active, or rank by outcome attribute with rankByOutcome + rankByOutcomeAttribute
  • Plot outcome0.priceCollateralToken.c (close price) for each market as a line to get the multi-candidate probability chart
  • You can also pass explicit marketIds instead of using ranking to choose which markets to chart

Step 4: Event-Level Aggregated Charts

For charts showing aggregated activity across the entire event (total volume, liquidity, open interest over time), use predictionEventBars.
Test this query in the Explorer →
query EventBars {
  predictionEventBars(
    input: {
      eventId: "yourEventId"
      from: 1773100000
      to: 1773700000
      resolution: hour1
    }
  ) {
    eventId
    bars {
      t
      volumeUsd
      buyVolumeUsd
      sellVolumeUsd
      totalVolumeUsd
      trades
      uniqueTraders
      liquidityUsd {
        o
        h
        l
        c
      }
      openInterestUsd {
        o
        h
        l
        c
      }
    }
  }
}
  • This aggregates data across ALL markets in the event
  • Use for volume bar charts, liquidity area charts, and open interest line charts
  • buyVolumeUsd / sellVolumeUsd breakdown enables buy/sell pressure analysis
  • uniqueTraders shows participation growth over time

Step 5: Trade Feed

Show recent trades across all markets in the event with predictionTrades.
Test this query in the Explorer →
query EventTrades {
  predictionTrades(input: { eventId: "yourEventId", limit: 50 }) {
    items {
      marketId
      outcomeId
      protocol
      tradeType
      maker
      traderId
      timestamp
      outcomeIndex
      outcomeLabel
      priceUsd
      priceCollateral
      amount
      amountUsd
      transactionHash
      networkId
    }
    cursor
  }
}
  • Returns trades across all markets in the event, sorted by most recent
  • Each trade includes the outcomeLabel and outcomeIndex so you can show “Bought Yes @ $0.65”
  • cursor enables pagination for loading more trades
  • traderId can be used to link to trader profiles
  • Can also query by marketId for single-market trade feeds

Step 6: Single Market Drill-Down

When a user clicks on a specific market within the event, fetch detailed chart data and token holder information.
Test this query in the Explorer →
query MarketDrillDown {
  predictionMarketBars(
    input: {
      marketId: "yourMarketId"
      from: 1773100000
      to: 1773700000
      resolution: hour1
    }
  ) {
    marketId
    bars {
      t
      volumeUsd
      trades
      uniqueTraders
      openInterestUsd {
        o
        h
        l
        c
      }
      outcome0 {
        priceCollateralToken {
          o
          h
          l
          c
        }
        liquidityCollateralToken {
          o
          h
          l
          c
        }
        bidCollateralToken {
          o
          h
          l
          c
        }
        askCollateralToken {
          o
          h
          l
          c
        }
        volumeUsd
        trades
        buys
        sells
      }
      outcome1 {
        priceCollateralToken {
          o
          h
          l
          c
        }
        liquidityCollateralToken {
          o
          h
          l
          c
        }
        bidCollateralToken {
          o
          h
          l
          c
        }
        askCollateralToken {
          o
          h
          l
          c
        }
        volumeUsd
        trades
        buys
        sells
      }
    }
  }
}
Test this query in the Explorer →
query TokenHolders {
  predictionTokenHolders(
    input: { marketId: "yourMarketId", tokenId: "yourTokenId", limit: 25 }
  ) {
    items {
      walletAddress
      amount
      predictionTrader {
        alias
      }
    }
    total
    cursor
  }
}
Getting the tokenId: The tokenId is extracted from the outcomeIds array on the market object (returned in Step 1). Each outcomeId is a compound string like 46553455570564517989191023458705371521436514261892866503067981558938998232024:Polymarket:0xc5d563a36ae78145c45a50134d48a1215220f80a:137. The tokenId is just the first segment before the first colon (e.g., 46553455570564517989191023458705371521436514261892866503067981558938998232024).For a binary market, outcomeIds[0] is the “Yes” token and outcomeIds[1] is the “No” token. Query once per outcome to get holders for each side.
  • Market bars give per-outcome OHLC data for price, liquidity, bid, and ask, enabling candlestick charts and bid/ask spread visualization
  • Token holders shows who holds the most of each outcome token, with their trader alias if available
  • Token holder data is only available for Polymarket (on-chain ERC-1155 tokens on Polygon). Kalshi does not expose holder data.

Putting It All Together

Here’s the recommended data flow for an event dashboard: On page load (parallel queries):
  1. detailedPredictionEventStats: event metadata, market list, aggregated stats
  2. filterPredictionMarkets(eventIds): current outcome pricing for all markets
  3. predictionEventTopMarketsBars: multi-market probability chart data
  4. predictionEventBars: event-level volume/liquidity charts
After initial load:
  1. predictionTrades(eventId): trade feed
On user interaction (drill-down):
  1. predictionMarketBars: when user clicks a specific market
  2. predictionTokenHolders: when user views holders tab
To alert on a market without polling — volume spikes, price moves, or trade-count bursts over rolling windows — set up a prediction market metrics webhook. See Webhooks for setup.
Optimizing calls: Queries 1-4 are independent and can be run in parallel to minimize page load time.Probabilities: The bestAskCT or priceCollateralToken.c values represent implied probability when the collateral token is a stablecoin. A price of 0.65 means the market implies a 65% chance.Multi-outcome events: Each market is binary (two outcomes), but an event can have many markets. For a “Who wins the election?” event, each candidate gets their own market.CT vs USD: Collateral token values are more precise for prediction markets since they avoid exchange rate fluctuations.Sorting the market list: Rank by outcome0.bestAskCT DESC to show the highest-probability outcome first, or by volumeUsd24h DESC for most active.Status values: Events and markets can be OPEN, SUSPENDED, or RESOLVED.
Check out the related endpoints in their respective API reference pages: