Data sources
public, keyless, with limits.
Every source is public and needs no key. Each has limits, and the pages state them instead of hiding them.
01Kalshi
- Base URL
https://api.elections.kalshi.com/trade-api/v2:/series(fee type and multiplier),/events/fee_changes,/events?status=open&with_nested_markets=true,/markets/orderbooks. - Server-side only: any request with an
Originheader gets 403. - At most 1,200 events per run by default (
--max-events). - Prices are decimal dollars; the order book returns bids only, so a YES ask is 1 − best NO bid.
Kalshi fee formula
taker fee = ceil_to_$0.000001( 0.07 × C × P × (1 − P) × fee_multiplier )
maker fee = ceil_to_$0.000001( 0.07 × 0.25 × C × P × (1 − P) × fee_multiplier )
C is contracts, P the price in dollars. The multiplier is read live per series, with any event override on top. Example: 1 contract at $0.055 with a multiplier of 1 gives a model fee of $0.00363825, which matches Kalshi's published worked example. A fee type without a published rate is reported as unknown. Deposit, withdrawal and wire costs are not included. Source: scanner/src/fees/kalshi-fees.js.


02Polymarket (on the GitHub runner)
- Markets: Gamma
https://gamma-api.polymarket.com/markets/keyset, open markets only, with a safety ceiling of 50,000 markets. Hitting it is recorded as truncated inboard.json. - Order books:
POST /bookson the CLOB host (https://clob.polymarket.com, overridable withPOLYMARKET_CLOB_HOST). Markets without a book show unknown depth. - Fees are unknown. No live fee schedule is fetched, so every Polymarket fee is reported as
unknown, never guessed. - Kalshi often has no settlement deadline where Polymarket has one; that is why the settlement veto rejected every cross-venue pair in the committed runs.
03Polygon (the Terminal)
- Contract: Polymarket's CTF Exchange V2,
0xE111180000d2663c0091e4f400237545b87b996b. - RPCs: by default
polygon-bor-rpc.publicnode.com,polygon.drpc.org,1rpc.io/matic, tried in that order; public and keyless. To use your own endpoint, set the GitHub secretPOLYGON_RPC_URL(how): it is tried first, the public ones stay as the fallback, and the file and the page name it only asown RPC (POLYGON_RPC_URL), never by its URL. The RPC URL in the admin is used by the Status check only. - Events decoded:
OrderFilled,OrdersMatched,FeeCharged: side, token, size, price, fee and builder code. - Window: 40 blocks, about one minute, labelled in blocks and chain time.
- Market icons are identicons drawn from the token id. The Terminal loads no market images from a venue host, so a visitor's browser talks only to your site.
- The chain has no order book, best bid and ask, or depth. The Terminal says "No order book". A price from fills is a last-traded price.

04Market titles
The chain knows token ids, not questions. titles.js asks Gamma on the runner and writes the questions into tape.json. If Gamma cannot be reached it writes titles.status: "unavailable" and the Terminal shows shortened token ids.
05The cross-venue matcher
Text similarity only filters. Matcher 0.3.0 compares subject, year, predicate, numeric thresholds, party, person, resolution source and settlement time; any contradiction rejects the pair. The best a machine verdict can be is candidate. Only pairs a person confirmed in the admin are priced.
06Honesty rules in the code
- A value a venue does not publish is
nullin the data andunknownon the page. - An unreachable venue reports zero markets; the workflow fails if it does not.
- Spreads count every fee on every leg and are divided by the days the money is locked. Simple annualisation comes first; the compounded figure is secondary and labelled.
- A multi-outcome Kalshi event counts only when it lists a catch-all leg; otherwise an unlisted outcome could pay every leg $0.
- Data is as fresh as the last refresh run, and every page shows how old its file is.