Skip to main content

Building Market Views

This guide explains how the discovery and orderbook endpoints compose to power a prediction market UI — from the home page event grid down to the live trading view.
Live discovery, orderbook, and routing surfaces include active venues only. Retired venue identifiers can still appear in historical positions, activity, and claim flows.

Data model overview

Note that matchedVenueMarkets hangs off each market, not off the event. See Matched Clusters for how cross-venue linkage works and which id to use as a join key. Key IDs the frontend threads through:
Prices are not included in discovery responses. GET /venue-events and GET /venue-markets return the market structure (events, markets, outcomes) but no outcome prices. Fetch live prices in a separate batch call to GET /midpoints using the venueMarket.ids you collected (see Bulk midpoint fetch), or subscribe to the WebSocket midpoint stream for continuous updates.

1. Home page — event grid

Fetch the top events sorted by volume. The default sort is volume desc and the default feed uses category-interleaved ranking for diversity.
For matched-only events (cross-venue):
The list returns one row per matched cluster, and each embedded market carries its counterparts on other venues in matchedVenueMarkets[]. See Matched Clusters for how the cluster is assembled and which id to join on. Response shape (simplified):
What to render: Each event becomes a card. Show title, image, and the first market’s outcomes. For the price display, batch the page’s venueMarkets[].ids into one GET /midpoints call (see Bulk midpoint fetch) and key the returned per-outcome midpoints by venueMarketOutcomeId. If multiple venues are present, the midpoints response also carries each sibling’s mark so you can show the best price across venues. Use venues and venueCount to display venue badges (e.g. “Available on Polymarket + Limitless”) without needing to inspect nested markets.
The embedded venueMarkets on list items is a preview — up to three markets chosen to represent the event on a card, not the complete set, and not necessarily the largest ones. Render counts and totals from marketCount, or fetch the full list from GET /venue-markets?venueEventId=. The detail endpoint (GET /venue-events/:id) returns markets uncapped.
Pagination: Use cursor for infinite scroll. Pass nextCursor as cursor in the next request.

2. Event detail — market list

When the user clicks an event card, fetch the full event detail including all markets and their cross-venue matches:
Each market in the response includes matchedVenueMarkets — the same market on other venues with their outcomes.
Deprecation: the embedded venueMarkets array on GET /venue-events/:id is deprecated and will be removed. Fetch an event’s markets from GET /venue-markets?venueEventId= instead — it is filterable, paginated, and returns the same matched siblings per market. Markets are still embedded by default today; once you’ve migrated you can request the lean response by sending the expand query without markets (e.g. ?expand=). A future release will make lean the default — send ?expand=markets to keep them inline across that change. The per-item description on the list endpoint (GET /venue-events) is likewise deprecated — fetch the full event (with description) via GET /venue-events/:id.
For the market list, use venue-markets:
Both endpoints return matched siblings per market. Event detail response (GET /venue-events/:id):
Use matchedVenueMarkets on each market to collect the venueMarket.ids for the GET /midpoints batch call (cross-venue price comparison) and the venueMarketOutcome.id values for orderbook subscriptions. Venue markets response (GET /venue-markets):
What to render: Each market is a row or card. Show the question, outcomes, and volume, with prices from the batched GET /midpoints call. matchedVenueMarkets gives you the same market on other venues — include those ids in the midpoints batch for cross-venue price comparison.

3. Market detail — live orderbook

When the user selects a specific outcome to trade, fetch the live orderbook.

Single-outcome orderbook

For a single outcome on a single venue:
Returns per-venue bid/ask levels:

Merged cross-venue orderbook (aggregated view)

To show a merged orderbook across multiple venues for the same market, pass multiple venueMarketIds from matched markets. You get these IDs from matchedVenueMarkets in step 2.
The response includes per-venue orderbooks keyed by venue name, plus metadata about matched markets:
How to build a merged view:
  1. From step 2, collect the primary market id and all matchedVenueMarkets[].id values
  2. Pass them all as venueMarketIds to GET /orderbooks
  3. The response groups orderbooks by venue under venueOrderbooks
  4. Merge bids/asks client-side: combine all venue bids at the same price level, sort descending. Same for asks ascending. Each level shows the total size and per-venue attribution
  5. matchedMarkets tells you which other venues have this market and whether they have orderbook data (hasOrderbook)
The @agg-build/sdk useLiveMarket hook and the WebSocket aggregated orderbook handle this merging automatically when you subscribe with multiple outcome IDs.

WebSocket orderbook (live updates)

After the initial REST load, subscribe to the WebSocket for real-time updates. Pass outcome IDs from both the primary and matched markets to receive the aggregated cross-venue stream:
The WebSocket aggregated orderbook snapshot already includes per-venue attribution and merged levels:
You’ll receive a full snapshot followed by incremental deltas. See the WebSocket Protocol docs for sequencing, checksums, and resync logic.

4. Bulk midpoint fetch — matched events and markets

When you want a price-comparison view across many events at once (e.g. a homepage grid that shows live “best price across venues”), you typically:
  1. List matched events — only events confirmed to exist on more than one venue.
  2. Collect every venueMarketId — the event’s own markets plus their matchedVenueMarkets.
  3. Fetch midpoints in one batch callGET /midpoints accepts up to 200 IDs.

List matched events

Each event’s response includes venueMarkets[] (the event’s markets) and, because we passed confirmed match statuses, the markets from sibling events on other venues. Walk the response to gather every venueMarketId you’ll want a midpoint for:

Batch midpoints

Pass the collected IDs to /midpoints. The endpoint proxies the live orderbook engine and returns the current Yes-side mark per market, plus per-outcome midpoints and the sibling markets the engine considered.
Each entry includes the headline midpoint, per-outcome midpoints, and the matched siblings the engine considered. See the API Reference for the full response schema, including markSource provenance.
Cap each request at 200 IDs. For larger universes, chunk the IDs into batches of 200 and fire the requests in parallel — the endpoint is read-only and idempotent.
For a worked SDK example that compares prices across venues, see Comparing Venue Prices.

5. Trading — smart route and execution

When the user wants to place a trade, compute the optimal route across venues:
This returns a quote with the best fills across all active venues where the market is available:
Execute the quote:
Track progress via WebSocket order_event messages (step progress, fill confirmation, errors).

Deep cost estimate (deepEstimate=true)

Some venues require one-time setup before a user can trade — ERC-20 and venue contract approvals on the venue’s chain (Polymarket / Polygon, Limitless / Base, predict.fun / BNB). These are paid through the gas paymaster on the user’s first BUY on each (venue, chain) pair and never again. Add deepEstimate=true to the route call to surface those costs in the response:
The response’s feeBreakdown then includes:
  • setupCosts — one entry per setup item the route would touch, with kind: "chainApproval" | "venueMarketAta", the cost in USD, and an alreadyPaid flag indicating whether the user has already settled it on a prior fill. venueMarketAta remains in the response type for historical compatibility; active venue routes use chainApproval.
  • setupCostsTotal — sum of costUsd for entries where alreadyPaid: false. This is also folded into the top-level totalCostIncFees so a single number reflects the realistic total the user will see at execution time.
Use the per-line alreadyPaid to render strike-through “first-time fee” chips for new users without double-charging returning ones. The deep surface is buy-only (sells never trigger first-time approvals) and is omitted on quotes where the engine could not produce an executable plan (status !== "ok").

End-to-end data flow

Filters reference

/venue-events

/venue-markets

Comparing Venue Prices

Fetch matched events and their midpoints to build a cross-venue price comparison.

WebSocket Protocol

Live orderbook, trades, and order events over WebSocket.

Real-Time Orderbook

SDK and hooks for live orderbook rendering.