> ## Documentation index
> Fetch the complete documentation index at: https://docs.predictefy.com/llms.txt
> Use it to discover every available page before exploring further.

# Compare one market across every venue

> Resolve a market to its cluster, line up every venue's price, and label each one honestly.

"Will the Fed cut in January?" trades on several venues at once, under different titles,
different tickers, and occasionally different resolution rules. This recipe lines them up.

## The one-call version

`compareMarketPrices` exists for exactly this. Give it a market on any venue and it returns the
cross-venue comparison directly — no cluster lookup needed.

```sh
curl -s "$PREDICTEFY_API_URL/api/kalshi/compareMarketPrices?marketId=MARKET_ID&live=true" \
  -H "Authorization: Bearer pk_live_YOUR_KEY"
```

It takes `marketId` **or** `slug`, plus `live`, `limit`, `offset` and `page`. Each row is one
venue:

```json
{
  "success": true,
  "data": [
    {
      "market": { "...": "the normalized market record for this venue" },
      "venue": "kalshi",
      "clusterId": "clr_9f2a7c41",
      "similarity": 0.94,
      "reasoning": null,
      "bestBid": 0.412,
      "bestAsk": 0.418,
      "indicativeYesPrice": 0.415,
      "indicativeNoPrice": 0.585,
      "label": "indicative price discrepancy",
      "asOf": "2026-08-12T14:31:04.882Z"
    }
  ],
  "meta": { "live": true, "liveUnavailable": false }
}
```

Two pairs of price fields, and the difference matters:

- **`bestBid` / `bestAsk`** come from the live book overlay. They are **never** a stored
  snapshot — if the overlay could not run, they are null rather than stale.
- **`indicativeYesPrice` / `indicativeNoPrice`** are the catalog's view, which may be a stored
  value.

Check `meta.liveUnavailable` before you present anything as live. When it is true, the live
overlay was requested and did not succeed, and the row is telling you so instead of quietly
serving you older numbers.

## The cluster route

Use this when you want the grouping itself rather than one market's neighbours.

```sh
# Browse clusters. Note: filters are category / hasDiscrepancy / sort — there is no
# text search on this route. Find the market first with fetchMarkets, then compare.
curl -s "$PREDICTEFY_API_URL/v1/clusters?hasDiscrepancy=true&limit=20" \
  -H "Authorization: Bearer pk_live_YOUR_KEY"

# Expand one cluster into its members.
curl -s "$PREDICTEFY_API_URL/v1/clusters/CLUSTER_ID" \
  -H "Authorization: Bearer pk_live_YOUR_KEY"
```

A cluster carries `question`, `normalizedQuestion`, `category`, `venueCount`, `venues`,
`hasDiscrepancy`, `aggAvgYes`, `aggSpread`, `maxSpread`, `similarity`, `closeDate` and `asOf`.
Expanding it adds `members`, each with `marketPk`, `venue`, `yesPrice`, `noPrice`, `volume24h`,
`liquidity` and its own `similarity`.

## Standing gaps

`/v1/discrepancies` lists clusters that currently disagree on price. It filters on `category`
and `live` — **not** by cluster id — and each row is a spread with its two ends:

```json
{
  "clusterId": "clr_9f2a7c41",
  "question": "Will the Fed cut rates at the January 2026 meeting?",
  "venues": ["kalshi", "polymarket"],
  "spread": 0.023,
  "low": { "venue": "kalshi", "canonicalMarketId": "kalshi:FED-26JAN-CUT", "yesPrice": 0.415 },
  "high": { "venue": "polymarket", "canonicalMarketId": "polymarket:0x7d3f", "yesPrice": 0.438 },
  "similarity": 0.94,
  "matchProbability": 0.97,
  "label": "indicative price discrepancy",
  "asOf": "2026-08-12T14:31:04.901Z"
}
```

`label` has exactly one permitted value here — `indicative price discrepancy`. That is not
hedging: this route makes no claim about depth, fees, or resolution equivalence, so it cannot
call anything executable.

To ask whether one of these survives those checks, qualify it:

```sh
curl -s "$PREDICTEFY_API_URL/v1/discrepancies/CLUSTER_ID/qualification?size=1000" \
  -H "Authorization: Bearer pk_live_YOUR_KEY"
```

That route takes `size` and an optional `venues` filter. See
[the scanner recipe](/guides/cookbook/arbitrage-scanner/) for what qualification actually
tests.

## Reading the comparison honestly

- **`similarity` is a match score, never a confidence.** A 0.94 pair can still settle
  differently. `matchProbability` is a separate field and a separate claim.
- **Render `asOf` next to every price.** Presenting a snapshot as live is the most common way a
  comparison UI misleads the person reading it.
- **Label the book type per row.** Some venues serve reconstructed books — faithful as price,
  not executable as depth. [Venue coverage](/reference/venues/) records which venues have a real
  book; read it from there rather than hard-coding a list that will go stale.
- **Handle `NOT_SUPPORTED` per row, not per request.** One venue that cannot serve a book should
  not blank the table. See [Capability-honest data](/guides/honest-data/).
- **`page.total` may be `null`** — that means not counted, not zero. Paginate on `hasMore` and
  `nextCursor`.

## Cost

Cluster lookups and cross-venue comparisons are priced above catalog reads because each one
walks stored relationship data. A fresh AI-assisted match, for a market with no existing
cluster, costs considerably more than reusing one — so cache the cluster id, not the prices.
Current weights are in [Credits & billing](/guides/credits/).

## Related

- [Scan for qualified cross-venue opportunities](/guides/cookbook/arbitrage-scanner/) — whether a gap is tradeable
- [Cross-venue data](/guides/cross-venue/) — how matching works
- [Prediction markets](/guides/prediction-markets/) — why venues legitimately disagree
