Prediction Stack docs
v1.0.0
Live app Get help
● Reference · What the data can and cannot say

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 Origin header 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.

Spread Research: checks evaluated, 0 positive after fees, cross-venue pairs scored, Kalshi fee model
The Scanner on the committed snapshot (runner run of 2026-09-25).
Scanner Spreads section: Positive after fees only is off by default, 122 of 122 listed rows match; cross-venue shows 24,724 pairs scored and 0 confirmed
The Spreads table opens on all 122 listed rows; "Positive after fees only" is off by default. Captured from release 1.0.0 on 2026-09-29.

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 in board.json.
  • Order books: POST /books on the CLOB host (https://clob.polymarket.com, overridable with POLYMARKET_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 secret POLYGON_RPC_URL (how): it is tried first, the public ones stay as the fallback, and the file and the page name it only as own 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.
Prediction Terminal: notional, fills decoded, traders and fees charged from Polygon, flow per block and the latest fills
The Terminal on the committed tape (40 blocks, block 94,417,942).

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 null in the data and unknown on 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.