Market data

Correlated Markets

Find markets connected to another market by generated real-world outcome signals

Correlated Markets starts from one prediction market and returns events that may become more relevant if that market resolves a certain way. Use it for related-market rails, portfolio ideas, hedge discovery, and thematic search that goes beyond title matching.

All endpoints are app-tier: send x-app-id, no user token. Your app's venue and category exclusions still apply. Closed and resolved markets are left out unless you pass includeResolved: true. Free-text matching (q on resolve, and the title fallback of a text query) always searches open markets only; resolve a closed or resolved market by venue + externalId, slug or conditionId instead.

Endpoint map

EndpointUse whenSDK method
POST /correlated-markets/resolveYou have a venue id, external id, slug, condition id, or text and want candidates in one call.resolveCorrelatedMarkets
GET /correlated-markets/cascade/{venueMarketId}You already have an sufwan-local-test venueMarketId and want expand or hedge candidates.getCorrelatedMarketCascade
GET /correlated-markets/connections/{venueMarketId}You want related events for a market, without choosing a side or mode.none, use REST
GET /correlated-markets/{venueMarketId}You want the generated Yes/No signals for a market.getMarketCorrelatedSignals
POST /correlated-markets/queryYou want free-text search across generated signals.queryCorrelatedMarkets

Expand vs hedge

  • mode: "expand" returns Yes-side events that become more attractive if your thesis is right.
  • mode: "hedge" returns Yes-side events that become more attractive if your thesis is wrong. Hedge results leave out the expand results for the same market and side.

Resolve a market

Use resolve when your app stores venue-native identifiers. It resolves the market, checks whether signals exist, and returns a paginated cascade.

SDK
import { createAggClient } from "@agg-build/sdk";

const client = createAggClient({ baseUrl: "https://api.t.sufwankhalid.com", appId: "your-app-id" });

const result = await client.resolveCorrelatedMarkets({
  venue: "polymarket",
  externalId: "123456",
  side: "yes",
  mode: "expand",
  limit: 10,
});

if ("status" in result && result.status === "processing") {
  // Signals are still being generated. Send the same request again later.
} else {
  console.table(result.data);
}

externalId on resolve is not externalIdentifier and not the webhook partner id. 202 means still generating ({ status: "processing" }).

If signals do not exist yet, generation starts and the response says so:

{
  "market": { "id": "vm_abc123", "question": "Will oil close above $100 this year?" },
  "status": "processing",
  "message": "Correlated market generation queued"
}

Send the same request again after generation finishes.

Use an sufwan-local-test market id directly

If you already have a venueMarket.id from GET /venue-events or GET /venue-markets, call the cascade endpoint. This path does not resolve identifiers.

const cascade = await client.getCorrelatedMarketCascade({
  venueMarketId: "vm_abc123",
  side: "yes",
  mode: "hedge",
  limit: 20,
});

if (cascade.nextCursor) {
  const nextPage = await client.getCorrelatedMarketCascade({
    venueMarketId: "vm_abc123",
    side: "yes",
    mode: "hedge",
    limit: 20,
    cursor: cascade.nextCursor,
  });
}

limit is capped at 100. Page with the returned nextCursor.

Result shape

Each result is an event-level candidate. Use venueEventId to fetch the event or link to it.

{
  "venueEventId": "ve_oil_supply",
  "eventTitle": "OPEC production cut",
  "eventStatus": "open",
  "eventStartDate": "2026-06-18T00:00:00.000Z",
  "eventEndDate": "2026-07-01T00:00:00.000Z",
  "score": 0.72,
  "action": "BUY YES",
  "reason": "Energy markets tighten as supply risk rises",
  "reasonDomain": "energy"
}

Inspect generated signals

Each market has a set of generated Yes/No signals: short statements about which real-world states become more or less likely if the market resolves a given way. They drive the cascade and connection endpoints. Fetch them to render "why this is related" copy.

const batch = await client.getMarketCorrelatedSignals("vm_abc123");

for (const signal of batch.signals) {
  console.log(signal.side, signal.direction, signal.domain, signal.text);
}

Connections without side or mode

connections returns related events for a market without a side or mode. Use it for a single "Related markets" rail on an event page.

curl -H "x-app-id: YOUR_APP_ID" \
  "https://api.t.sufwankhalid.com/correlated-markets/connections/vm_abc123?limit=10"

Page with nextCursor. Pass includeResolved=true to include resolved and closed markets.

Search by theme

Use query search when the user starts from a theme instead of a market. Results carry market and event status and dates, so you can keep resolved markets out of tradeable recommendations. Set direction to more_likely or less_likely to filter, or balanced: true to mix both in one page.

const { results } = await client.queryCorrelatedMarkets({
  text: "oil supply shock raises inflation risk",
  limit: 10,
  balanced: true,
});

for (const match of results) {
  console.log(match.marketQuestion, match.marketStatus, match.eventEndDate, match.score);
  console.log(match.matchSource, match.matchedSignal.direction, match.matchedSignal.text);
}

On this page