# How to match the same question across venues

No two venues share an identifier, so lining one outcome up on Kalshi and Polymarket is a judgement. What to match on, and what to write down.

*https://predictionmarkets.tools/how-to/match-a-question-across-venues · next to Prediction Market Data APIs*

**Answer:** There is no identifier that two venues share, so every match is somebody's judgement. Read the two rule texts rather than the two titles, and match on the named settlement source, the close moment in UTC, the fallback clause and which side is YES. Rented matchers exist — Predictefy groups equivalent markets into clusters, Adjacent publishes one rate with the spread between its sources — and each is a judgement too.

## The approaches, in order

1. [Polymarket Gamma API](https://predictionmarkets.tools/tools/polymarket-gamma-api.md) — Free and keyless. Every market record carries its condition id, its outcome token ids and the resolution rules text — the rules are what you match on.
2. [Kalshi API](https://predictionmarkets.tools/tools/kalshi-api.md) — Series, then events, then markets. The series record names the settlement source and links the contract terms; REST market data answers without an account.
3. [Predictefy](https://predictionmarkets.tools/tools/predictefy.md) — A clusters endpoint that groups equivalent markets across sixteen venues, with a similarity score its own documentation refuses to call a probability.
4. [Adjacent](https://predictionmarkets.tools/tools/adjacent.md) — Reference rates — one series built from the same question on more than one venue, published beside the spread between its sources rather than instead of it.
5. [Brier.fyi](https://predictionmarkets.tools/tools/brier-fyi.md) — An open-source set of hand-approved cross-platform matches with a published tolerance rule. Read the methodology; its pipeline is paused.

*Ordered editorially. Paid placement does not affect this order.*

## The short way

Open both records and read the rules, not the titles.

On Polymarket the record comes from [the Gamma API](https://predictionmarkets.tools/tools/polymarket-gamma-api), free and with no
key: it carries the `conditionId` for the market, a token id for each outcome, the start and end
dates, and the resolution rules text. On Kalshi the same question arrives through
[the Kalshi API](https://predictionmarkets.tools/tools/kalshi-api) as a tree — a series, its events, and the markets under them —
where the series record carries a `settlement_sources` list with the name and URL of the source
plus links to the contract terms and the product certification filed with the CFTC. Both surfaces
answer unauthenticated reads, so the matching work costs attention rather than money.

Then build the match out of four things, none of which is the title: **the source each rule text
names**, **the close moment in UTC**, **the fallback when the source does not publish**, and
**which side of the question each venue calls YES**. If all four agree, you have a pair. If one
disagrees, you have a decision to record rather than a pair to file.

Record it as a row with the reason attached, because in six months nobody remembers why two
markets were grouped.

```yaml
# A match is a record with a reason attached, not a join key.
- id: <your own id for the question>
  kalshi:
    market: <ticker, from the series then event then market tree>
  polymarket:
    condition_id: <conditionId, from a Gamma market record>
    yes_token: <the outcome token id for the side you are calling YES>
  yes_means: <one sentence, in your words, that is true of both legs>
  settlement_source: <the source each rule text names, written out twice>
  closes: <both close moments, in UTC, not in the venue's local wording>
  accepted_difference: <what you decided could not change the outcome>
  matched_on: 2026-09-21
```

The `accepted_difference` field is the whole point. A table of matched questions with no record of
what was accepted is a table nobody can audit, including you.

## What the options are

[The Polymarket Gamma API](https://predictionmarkets.tools/tools/polymarket-gamma-api) is the read half of Polymarket and takes no
credentials at all. The two identifiers everything else on that venue is keyed by come out of
here — the condition id and the outcome token ids — and the field worth more attention than it
gets is the rules text, where the real source and the edge cases live. One structural detail
matters for matching specifically: markets are grouped as **events with child markets**, one event
holding many tradeable questions, each with its own pair of outcome tokens. An event is not a
question, and matching at the event level quietly groups things that resolve separately.

[The Kalshi API](https://predictionmarkets.tools/tools/kalshi-api) is the most conventional surface in this category and reads
like a futures venue. The series is where the matching evidence sits: the exchange resolves its own
markets under the rules of each series, and the series record exposes the named settlement sources
with their URLs, the contract terms, and the product certification filed with the CFTC. Two
practical notes. REST market data answers unauthenticated requests, so a candidate pair can be read
without an account on either side. And archived markets move to a parallel set of historical
endpoints behind a cutoff that keeps advancing — a matcher written only against the live endpoints
loses its tail.

[Predictefy](https://predictionmarkets.tools/tools/predictefy) rents you the matching. Its documentation describes a matching
engine of embedding similarity plus LLM validation that groups equivalent markets into **clusters**
across sixteen venue ids, with a `/v1/discrepancies` layer reporting price gaps between cluster
members. What makes it worth citing is the honesty of the field it hands back: each cluster member
carries a `similarity` score that the docs describe as the raw embedding similarity and say is
deliberately *not* called confidence, because it is not a calibrated probability that the markets
are equivalent. Resolution equivalence — that two markets truly settle on the same terms — is a
separate gate, and the discrepancy endpoints do not apply it. Nothing reads without a key, the free
plan is non-commercial with a seven-day history window, and a fresh AI cross-match is the most
expensive call on the meter at 25 credits.

[Adjacent](https://predictionmarkets.tools/tools/adjacent) solves a narrower version of the same problem and publishes the result
instead of the method. A **reference rate** takes the same underlying question priced on more than
one venue, combines the source prices into one series, and reports the `spread` between them —
volume-weighted, equally weighted, or by median. The rate list is `GET /api/v1/rates`, a single
rate is `GET /api/v1/rates/{rate_id}`, and the constituent prices come back from
`GET /api/v1/rates/{rate_id}/prices` with `sources=true`. The documentation's own caution is the
useful part: a small spread means the sources are close, and a large one tells you to inspect the
individual markets before treating the rate as a single signal. Coverage is Kalshi and Polymarket
only, and on 19 September 2026 every market the free public tier returned was Kalshi.

[Brier.fyi](https://predictionmarkets.tools/tools/brier-fyi) is the one published methodology for doing this properly, and it is
the bar the rest of the page is measured against. It generates embeddings to find similar markets,
refines with tags, keywords, duration overlap and other heuristics, and then has **real people pick
and approve every match**. The stated tolerance is that markets may be grouped only if their
differences would not have more than a one-percent chance of changing the resolution, and the site
names its own hard cases: two markets resolving on 31 December against 1 January, or using two
different news sources. The code is MIT and the matched set is readable — but the pipeline that fed
it is paused, the site's content is under a non-commercial licence, and most of what it scored
resolved in 2024 or 2025. Read it for the method, not for a current table.

## Where this breaks

**There is no shared identifier, so every match is somebody's judgement — including the rented
ones.** Kalshi's key is a ticker tree; Polymarket's is a condition id plus one token id per outcome
on a chain. Nothing derives one from the other and no registry maps between them, which means every
product on this page computed its matches from text. Predictefy says so about its own field in as
many words, and Brier.fyi's answer is to put a person at the end of the pipeline. A match that
arrives as a row in somebody's API is not more authoritative than one you made; it is the same kind
of object with the provenance further away. Store whose judgement it was.

**Fuzzy title matching fails exactly where it matters — on one clause.** "Above 90" and "at least
90" differ by one degree of outcome and by almost nothing to an embedding. So do a threshold
crossed *by* a date and one crossed *in* a year, a market on the winner of a contest and one on the
winner of the first round, and a question naming one agency's release against another's. These pairs
score high and resolve differently, which is the worst combination available: a matcher tuned to
catch them also groups genuinely distinct markets, and one tuned to avoid them misses the mirrors
it exists for. This is why the honest bar is a tolerance about the resolution rather than a
similarity threshold.

**"The same question" is usually false once you read both rule texts.** The named source differs —
one contract settles on a specific agency's first publication, the other on a named news outlet.
The fallback differs: some contracts hold expiration until a corrected release, others fall back to
a price determined by the exchange, and on Polymarket a UMA token-holder vote can return
**Unknown**, in which case the market resolves 50/50 and every token on both sides redeems at 50
cents. Who decides differs too — the exchange under its own series rules on one side, a bonded
proposal escalating to a vote on the other, with a disputed question running four to six days.
[Who decides how a prediction market resolves](https://predictionmarkets.tools/guides/who-decides-the-outcome) is the page to read
before a pair goes into the table.

**Time zones and cutoff moments are a second question hiding inside the first.** Close time,
expiration, and the last moment the source can still publish are three different timestamps, and
venues word them in three different ways. A temperature market is the clearest case: the day it
settles on runs midnight to midnight *local standard time* at one named station, regardless of when
either venue stops trading, and the number is preliminary for months afterwards —
[what a temperature market actually settles on](https://predictionmarkets.tools/guides/what-a-temperature-market-settles-on) works
through it. Normalise everything to UTC before comparing, and record the close moments separately
from the resolution moment, because it is the second one that decides whether two contracts answer
the same question.

**One venue's YES is the other's NO.** Polymarket's token ids are per outcome, so the side is an
identifier rather than a flag; Kalshi's markets carry a yes and a no side with the question worded
one way round. Two venues routinely mirror a question — "above" against "at or below", "wins"
against "does not win" — and a match that lines up the markets without lining up the sides inverts
a whole column silently. The same trap shows up inside a normalised feed:
[FinFeedAPI](https://predictionmarkets.tools/tools/finfeedapi) documents that its market ids are per outcome rather than per
question, so anyone counting markets or joining across venues has to carry that from the first
query.

**A gap between two matched prices is more often a failed match than a finding.** Fees are charged
on different bases, collateral is dollars on one side and a stablecoin on the other, the exits cost
and delay different amounts, and eligibility rules frequently stop one person holding both legs at
all — [why the same contract costs two different prices](https://predictionmarkets.tools/guides/why-the-same-contract-costs-two-prices)
takes the gap apart piece by piece. Predictefy's own documentation draws the same line: its
discrepancy endpoints indicate where to investigate, not what to do, and a row earns a stronger
label only once live-depth, verified-fee, open-market and resolution-equivalence gates have each
passed. Treat a persistent gap on a matched pair as evidence that the pair is wrong until the rule
texts say otherwise.

## If you outgrow this

If two venues are not enough, the rented versions are listed together:
[tools that cover more than one venue](https://predictionmarkets.tools/collections/cross-venue) is the collection, and
[Adjacent vs DepthFeed vs Predexon](https://predictionmarkets.tools/compare/cross-venue-prediction-market-data) is the head to
head. Every one of them flattens a difference to put two venues in one schema, and on a matched
question the difference being flattened is the one this page is about.
[PMXT](https://predictionmarkets.tools/tools/pmxt) offers cross-exchange market matching on its hosted tier under a wider venue
list, with the caveat its card carries: the library stopped shipping in July 2026.

If what you want next is the history behind each leg rather than the pairing,
[how to get resolved market history as data](https://predictionmarkets.tools/how-to/get-resolved-market-history) is the companion
page, and [Predexon](https://predictionmarkets.tools/tools/predexon) and [DepthFeed](https://predictionmarkets.tools/tools/depthfeed) are where a question about
the order book at a point in time goes. Neither of them does the matching for you.

If what you want is whether the two prices were any good rather than whether they were the same
question, [Brier.fyi](https://predictionmarkets.tools/tools/brier-fyi) already did both the matching and the scoring — read
[how accurate a prediction market's price actually is](https://predictionmarkets.tools/guides/how-accurate-the-price-is)
alongside it, and note that what you are reading is an archive with an unusually good method
attached.

## FAQ

### Is there an identifier two venues share for the same question?

No. Kalshi keys on a ticker tree of series, event and market; Polymarket keys on a condition id plus one token id per outcome, on a chain. Neither is derivable from the other, and no registry maps between them. Anything that lines the two up computed the match, and the match is a judgement rather than a lookup.

### Can I just match on the question titles?

Not safely. Two questions that differ by one clause — a date, a threshold, "at least" against "more than", a different named source — read almost identically to an embedding and resolve differently. Brier.fyi's published method runs embeddings first, then refines with tags, keywords and duration overlap, and then has a person approve every match.

### What tolerance should I accept when two contracts nearly agree?

Brier.fyi publishes the only stated bar in this catalogue: two markets may be grouped only if their differences would not have more than a one-percent chance of changing the resolution. That is a judgement about a specific pair, not a threshold you can compute, which is why its matches are approved by people.

### Does a price gap between two matched contracts mean one of them is wrong?

More often it means they are not the same contract. Different rule texts, different fallback clauses, fees charged on different bases, collateral in dollars against a stablecoin, and different close times all move one leg without moving the other. Read why the same contract costs two prices before treating a gap as a data error.

## Sources

1. [Cross-venue intelligence](https://docs.predictefy.com/guides/cross-venue/) — Predictefy, read 2026-09-21
2. [Reference rates](https://docs.adjacent.markets/explore/reference-rates) — Adjacent, read 2026-09-21
3. [About](https://brier.fyi/about/) — Brier.fyi, read 2026-09-21

*Last updated 2026-09-21. A reference page, corrected in place — not a dated post.*
