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
Every 6 hours Layer pulls all open markets from Kalshi and Polymarket — about 13,000 Kalshi events and 43,000 Polymarket events. 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 Polymarket, and the two Polymarkets 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).
3. Rule them out with hard checks
Code rejects a candidate — no AI involved — if:
- the dates are missing or too far apart,
- the market types differ (a game's winner vs its total points),
- 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.
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 AI models
What survives first gets a quick, cheap check from Jev: pairs it's confident are about different events (under 50% "same event") are dropped before the more expensive grader reads them. Grading runs as fast as it can, with a monthly spending limit.
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 graders, each reading both venues' full rules:
- Claude writes a verdict (same bet, same bet with differences, different), a confidence, the exact rule differences, and a one-sentence explanation.
- Jev, a separate classifier, answers the same questions with its own probabilities. It's asked about each outcome pairing Claude 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.
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 Claude is at least 90% sure, or Claude and Jev both 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.
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 opens a GitHub issue with both sides' details so the cause gets fixed. - 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), not from a wrong match, so it's counted separately.
The share of settled matches that agreed is how Layer measures its own accuracy.
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.