# How matching works

A wrong match is worse than no match: a bot that trusts it could bet both sides of what it thinks is one market and lose on both. So Layer only serves a match after several independent checks.

## 1. Pull every open market

Layer regularly pulls all open markets from Kalshi, Polymarket US and Polymarket (polymarket.com), Hyperliquid's outcome markets and Novig's game lines. Sports events are split by market type (winner, spread, total, side markets), and each side of a two-team Polymarket market becomes its own contract. NFL, NBA and NHL teams get their full names on both venues, since Kalshi names them by city ("Philadelphia") and Polymarket by nickname ("Eagles").

### Markets inside a game

A game is many bets, not one: the winner, spreads ("wins by more than 3.5"), totals ("over 44.5 points"), each half's and quarter's lines, team totals, and player props ("over 249.5 passing yards"). For the NFL, college football, NBA, WNBA, NHL and MLB, each is its own market type on both venues. Kalshi's `KXNFL1HSPREAD` series is a first-half spread and `KXNFLPASSYDS` is passing yards, the same as Polymarket's `first_half_spreads` and `passing_yards`. A pair must be the same type on both sides, so a first-half spread never meets the full game's spread, and a team's total never meets the game's total.

Every line names who it's about and where the line is, on both venues: "Aaron Rodgers over 124.5" is Kalshi's "Aaron Rodgers: 125+", and "Cleveland Browns over 10.5" is Kalshi's team total for the Browns. Polymarket's "Anytime Touchdown" is Kalshi's "1+" touchdowns, and "2+ Touchdowns" its "2+".

## 2. Find candidates

For each upcoming Kalshi event, Layer looks for Polymarket events in a compatible category, within a date window (±1 day for games, ±7 days otherwise), with similar titles. It keeps the best 5. Some Kalshi events outside sports give no date for the event itself, only when they settle by, often months later (the 2026 House race settles by 2027-02-01). For those, the window reaches back 120 days before that date, and the graders are told the date is a deadline. Polymarket pads some non-sports events with unpriced placeholder outcomes ("Party A" … "Party F") it can name later; Layer ignores them until they're priced. Once a Kalshi series has approved matches in a Polymarket series, Layer looks in that series directly, keeping only events of the same market type between the same two teams or players.

A game's other markets are found through the game itself: once one of its markets is matched (usually the winner), each Kalshi market in the same game is compared only with the Polymarket market of the same type in that same game. The two venues' titles for these share few words ("Philadelphia vs Chicago: Passing Yards" and "Eagles vs. Bears - Player Props"), so a text search would miss them.

### Polymarket US

Kalshi events are matched with Polymarket US (polymarket.us) the same way, as a separate set of matches: every match is Kalshi plus one other venue, and the other venues never mix. Polymarket US names its market types its own way (`football_team_full_game_spread`, `hockey_team_first_period_total`), so at ingest each is renamed to the type of the Kalshi series that is the same bet (`spreads`, `p1_totals`). The names don't always say what a type holds: `football_team_full_game_total` is the game's total and `football_team_points_full_game_total` is a team's, so the renaming was checked against the lines each type actually lists. A type with no Kalshi counterpart keeps its own name.

Polymarket US lists the big leagues' games under the same event slugs as polymarket.com (`nfl-dal-hou-2026-10-04` on both). So once a Kalshi event is matched with polymarket.com, the Polymarket US event with the same slug and market type is its candidate, and a game's other markets follow as above. Everything else goes through the same text search, hard checks and graders. Ask for Polymarket US matches with `?venue=polymarket_us` (see the [API reference](https://uselayer.sh/docs/api.md)). Since the two Polymarkets are never paired with each other, a polymarket.com market's Polymarket US twin is found through Kalshi: its Kalshi match, then that Kalshi market's Polymarket US match.

### Hyperliquid

Kalshi's events are also matched with Hyperliquid's outcome markets, a third separate set of matches. Games: winners (NBA, NFL, esports), soccer results (each team and the draw), and a game's totals and spreads. And, since November 2026, the rest Kalshi also lists: season winners (Super Bowl, NBA, MLB, Premier League and Champions League champions, each team its own contract; Hyperliquid lists a few teams, Kalshi every team, and only teams both list pair), crypto prices at a set time (BTC, ETH, SOL and HYPE above a price, against Kalshi's hourly price markets at the same hour; they pair only on a price level both venues list, which is rare, and they settle on different price feeds, Pyth on Hyperliquid and CF Benchmarks on Kalshi), and an IPO by a date (Anthropic). These are found by series, not by a text search, so a crypto price at the wrong hour is never offered. The Fed's rate decision is read but doesn't pair: Hyperliquid lists Decrease, No change and Increase, Kalshi lists each size of change. Hyperliquid's prices of its own perps (trade.xyz's S&P 500, oil, gold), touch markets and IPO market caps aren't matched. Hyperliquid writes every market from a template, and Layer fills the template's full rules in with the market's fields (teams, competition, start, what play counts, official source), so the graders read the same text Hyperliquid's own settlement does. Hyperliquid states every start in UTC: an NBA game Kalshi has on Oct 21 is Hyperliquid's Oct 22 at 12:30 AM UTC, so a stated start also counts on its US Eastern day. A Kalshi league only meets the Hyperliquid competition it can be (Kalshi's NHL game never pairs with Hyperliquid's NFL game of sides that read alike), and Kalshi's virtual eBasketball, eFootball and eSoccer games never pair with real ones. Each side of an outcome is its own contract, keyed by its coin (`#14960` is side 0 of outcome 1496). Ask for these matches with `?venue=hyperliquid`. Their settlements are checked like every other match's (`/v0/settlements?venue=hyperliquid`). `/v0/profit` and `/v0/size` don't take Hyperliquid yet.

<video class="portrait" src="/videos/docs/layer-hyperliquid-same-game.mp4" poster="/videos/docs/layer-hyperliquid-same-game.jpg" autoplay muted loop playsinline controls preload="metadata" aria-label="One Europa League game, Bournemouth vs AC Milan, on Kalshi, polymarket.com, Polymarket US and Hyperliquid: four different names, the same outcomes about a cent apart, the same rules, and one Layer call per venue."></video>

*One game on all four venues, Oct 22: different names, the same outcomes and rules, and one call per venue.*

### Novig

Kalshi's sports events are also matched with Novig (novig.com), a US sports exchange: a fourth separate set of matches, with Kalshi only. Game lines: moneylines, spreads, totals and soccer's three-way result, where each team's win and the draw are separate Yes/No markets on Novig and Layer pairs each one's Yes. Season futures, since November 2026: the Super Bowl, Stanley Cup, NBA and college football champions, the NBA Cup, the AFC and NFC champions, each NFL division, NFL and NBA playoff qualifiers and the NFL MVP, each team or player its own contract (the Yes of its Novig market), found by the one Kalshi series that asks the same question, and only teams or players both venues list pair. First-half moneylines, spreads and totals are read only when Layer's operator switches them on, since they add a few hundred pairs a week to grade; a first-half winner doesn't pair, as Kalshi's has a tie and Novig's has two sides. No player props. Layer reads Novig's open games from its public catalog and names both sides in full from the game ("Toronto Raptors at Los Angeles Clippers"). Novig publishes no contract rules text in its API, so the rules the graders read are a short summary Layer writes from Novig's fields, and it says what it doesn't know: whether overtime or extra time counts, and how a postponed game settles. Starts are stated in UTC and US Eastern, as for Hyperliquid. A Kalshi league only meets the same Novig league (Kalshi's NHL game never pairs with Novig's NFL game), and Kalshi's virtual games never pair with real ones. Each Novig outcome is its own contract, keyed `<marketId>:<outcomeId>`. Ask for these matches with `?venue=novig`; if they're ever switched off, asking for them answers `403 venue_not_served`. `/v0/profit` and `/v0/size` don't take Novig yet.

## 3. Rule them out with hard checks

Code rejects a candidate — no AI involved — if:

- either venue's rules are empty,
- the dates are missing or too far apart,
- for a sports game, the two venues' rules name different game days (two games of one series),
- one side is a women's league and the other the men's league of the same clubs (Liga F vs La Liga),
- the market types differ (a game's winner vs its total points),
- one side is a singles match and the other a doubles match (tennis, pickleball),
- one side is a ladder of thresholds and the other a set of ranges,
- the number of outcomes or the kind of line differs,
- no outcome on one side has the exact same line as an outcome on the other. "At least 60" and "above 60" are different lines: they pay differently if the result is exactly 60.

The same checks run again whenever a pair is approved, by the graders or by a person, so a pair that fails one by then (a check added later, or a date a venue moved) is rejected instead of going live.

One exception to the outcome count: elections. Each venue lists the candidates it chooses, so the two lists rarely have the same length. A named candidate pays out the same whoever else is listed, so a politics event whose outcomes are plain names (no lines) isn't rejected for its count. Only candidates both venues name can pair. A catch-all like "Other" or "Field" never pairs, because on each venue it covers different people.

Outcomes are paired the same way: a line only pairs with the same line about the same player or team. In a game's props, dozens of players share "over 0.5", so the line alone would pair the wrong players. Names count as the same when they differ only by accents ("Goias" / "Goiás EC"), length ("Atlanta" / "Atlanta Braves"), abbreviations ("Ind. Medellin", "St. Louis" / "Saint Louis") or initials ("Chicago WS" / "Chicago White Sox"). Teams that only share a word, like AC Milan and Inter Milan, never pair.

A single yes/no question on each side counts as one possible pairing, whatever the two venues label it ("Yes", "Before 2027", or the whole question). The graders decide whether it's the same question.

## 4. Grade with two independent graders

What survives first gets a quick screen: pairs that are clearly about different events are dropped before the full grading. Season winners on Novig and Hyperliquid skip it, since they're found by the Kalshi series that asks the same question, not by a text search.

The queue is worked in order of what matters soonest: events in the core series (listed under "Measuring what Layer misses" below) come first, soonest first, so this week's NFL, NHL and top soccer games are graded before they start. Other upcoming events follow, also soonest first, and events whose date has already passed come last. An event Kalshi dates only by when it settles is placed by Polymarket's earlier date for it. How similar the two listings look only breaks ties.

The rest go to two independent AI graders, each reading both venues' full rules:

- **The first grader** writes a verdict (*same bet*, *same bet with differences*, *different*), a confidence, the exact rule differences, and a one-sentence explanation.
- **The second grader**, built differently, answers the same questions with its own probabilities. It's asked about each outcome pairing the first grader confirmed on its own (each spread or total line, each Fed bucket), so a 25-line market is judged line by line, not all at once.

**Rule differences are also checked once per league.** Every game between one Kalshi series and one series on the other venue (Kalshi's NBA games and Hyperliquid's or Novig's NBA games, say) is written from the same rules, with only teams, dates and lines changed. So a stronger grader reads one live match of each pairing for the differences that hold for every game, such as the data source or whether overtime counts, and those flags go on every match of the pairing, along with any the match has of its own. Each pairing is checked again every month.

Both venues write the same rules for every line of a game, changing only the team, player and number. Layer shows the graders one line's rules, says so, and gives each pairing's own question from both venues ("Edmonton wins by over 1.5 goals", "Spread: Oilers (-1.5)"), so each line is judged by its own number.

## 5. Go live only when it's safe

A match goes live when **the first grader is at least 90% sure**, or **both graders say "same bet" at 80% or more**. Only the outcome pairings the graders confirmed are served; under the two-grader rule, that means only the lines both passed. Confident mismatches are removed; everything else waits.

### Crypto windows

Crypto markets repeat: a new "up or down in the next 15 minutes" window for BTC, ETH, SOL and XRP every 15 minutes, and a new set of "$X or above" and price-range lines at every hourly, daily and weekly close. Kalshi lists a 15-minute window only when it opens, so the search and graders above would find it too late. Instead, each kind of crypto market is approved once, by a person, as a template: both venues' rules with only the numbers, dates and times hidden. From then on, each new window goes live by itself if:

- both venues' rules read word for word like the approved template;
- the times in the rules are that window's own start and end;
- the window starts and ends at the same moment on both venues.

Anything else goes to a person, never live. A new 15-minute window is usually live about 30 seconds after it opens, and `match.live` goes out as soon as it is (see [webhooks](https://uselayer.sh/docs/api.md#webhooks)). Each templated match is checked against both venues' results within minutes of settling, and a single disagreement pulls every match that template made. The exception is a match marked `source_differs`: its venues read different prices, so a very close finish can settle differently without the match being wrong. It's recorded as a disagreement and stays live, with that caveat.

What's matched, all with Kalshi:

| | 15 minutes, up or down | "$X or above" | Price range |
|---|---|---|---|
| Polymarket US (`venue=polymarket_us`) | BTC, ETH, SOL, XRP | BTC, ETH, SOL, XRP: hourly, daily and weekly closes | BTC, ETH, SOL, XRP: hourly, daily and weekly closes |
| polymarket.com (`venue=polymarket`) | BTC, ETH, SOL, XRP | BTC, ETH: hourly closes | Not matched |

"$X or above" and price-range lines pair one by one, only at prices both venues list. Kalshi writes some lines one tick below the round price ("above $91.9999" for SOL, quoted to 4 decimals), which is the same line as Polymarket US's "$92 or above". Where the two venues use different price steps (Kalshi's daily ETH ranges are $40 wide, Polymarket US's $20), only the shared lines pair, sometimes none.

How each kind settles, and what `basis` and `caveats` say about it:

- **Polymarket US, 15 minutes:** both venues use CF Benchmarks' price index for the coin, averaged over the last 60 seconds. BTC, ETH and SOL are `identical`. XRP is `equivalent_with_caveats` with `rounding_differs`: Kalshi rounds XRP to 4 decimals and Polymarket US to 5, so a window that barely moves can settle Yes on Kalshi and Down on Polymarket US.
- **Polymarket US, "$X or above" and ranges:** the same index, but Polymarket US rounds the closing price and Kalshi's rules don't say it does: `rounding_differs`.
- **polymarket.com, 15 minutes:** polymarket.com settles on Chainlink's 60-second average, Kalshi on CF Benchmarks': `source_differs`.
- **polymarket.com, "$X or above":** polymarket.com settles on Binance's 1-hour candle close (the hour's last trade), Kalshi on CF Benchmarks' 60-second average: `source_differs` and `timing_differs`.

## After a match is live

If either venue edits the rules of a matched market, the match is pulled from the API (`rules_changed_pending_review`) and goes back to the two graders, who put it live again if it's still the same bet. A venue adding or dropping lines of a ladder isn't a rules edit: Polymarket US's fingerprint of an event's rules masks each line's number. Closed markets disappear on the next pull.

## Checking matches against real results

Every match is checked again once both markets resolve. Both venues publish the result, so Layer compares them:

- **Agreed** — both paid out the same way. The match was right.
- **Disagreed** — one paid Yes, the other No. The match was wrong. Layer pulls that event pair from the API (`needs_review`), records a plain-English explanation from both venues' rules, and flags it so the cause gets fixed. The one exception is a crypto window marked `source_differs`, which stays live (see [Crypto windows](#crypto-windows)).
- **Edge case** — one venue voided the market (for example, refunded a postponed game) while the other resolved it. That comes from the venues' settlement policies (see the [Overview](https://uselayer.sh/docs/index.md)), not from a wrong match, so it's counted separately.

The share of settled matches that agreed is how Layer measures its own accuracy. Every settlement of a match that was live in the API is served by [`GET /v0/settlements`](https://uselayer.sh/docs/api.md#get-v0-settlements), with its totals (and, with `series`, `category` or `polymarket_series`, the record for one kind of market), and `GET /v0/match` answers a settled market with its `settlement`.

## Measuring what Layer misses

Accuracy says whether live matches are right; coverage says how many should-be matches are live. Layer tracks a fixed list of core series both venues list — NFL, college football, NBA, WNBA, NHL, MLB, the top European soccer leagues, Champions League, MLS, ATP and WTA tennis, UFC, Fed decisions, CPI and jobs reports, and control of the House and Senate — and, for every upcoming event in them (next 14 days for sports, 60 for the rest; for an event dated only by when it settles, when the event itself could fall in that window), records the furthest it got: live, waiting to be graded, rejected by the graders, screened out, vetoed, no Polymarket look-alike found, or not searched yet. Not every event in those series is on Polymarket, so the share that's live is a floor.
