Guide
Compare one event across Kalshi and Polymarket
Build a side-by-side table: for each answer, the Kalshi price, the Polymarket price, how fresh each is, and the gap. Two API calls.
Steps
- Find the event with
/events?q=…and take itsslug. - Fetch it with
/events/{slug}. - Group outcomes from every market by
match.group_id. Outcomes withmatch: nullhave no partner on the other venue. - For each group with both venues, show each
quote.probabilityandquote.freshness. - Use
spreads[](joined onmatch.key) for the gap. Checkcomparisonandmatch.contract_compatibilitybefore calling two prices the same bet.
Code
Side-by-side table
import os
from collections import defaultdict
import requests
BASE = "https://api.thepredictionmarkets.com/api/public/v1"
HEADERS = {"X-API-Key": os.environ.get("TPM_API_KEY", "tpm_demo_key_authorized_2026")}
def get(path, **params):
resp = requests.get(BASE + path, params=params, headers=HEADERS, timeout=20)
resp.raise_for_status()
return resp.json()["data"]
slug = get("/events", q="democratic nominee 2028", limit=1)[0]["slug"]
event = get(f"/events/{slug}")
print(event["title"], "| comparison:", event["comparison"])
rows = defaultdict(dict) # group_id -> {"title", "key", "kalshi", "polymarket"}
for market in event["markets"]:
for outcome in market["outcomes"] or []:
match = outcome.get("match") or {}
if not match.get("group_id"):
continue # no partner on the other venue
row = rows[match["group_id"]]
row.update(title=outcome["title"], key=match["key"])
row[market["venue"]] = outcome["quote"]
gaps = {s["outcome_key"]: s["gap"] for s in event["spreads"]}
def fmt(q):
return f"{q['probability']:.3f} ({q['freshness']})" if q["probability"] is not None else "-"
for row in rows.values():
if "kalshi" in row and "polymarket" in row:
print(f"{row['title']:<28} kalshi {fmt(row['kalshi']):<16} polymarket {fmt(row['polymarket']):<16} gap {gaps.get(row['key'])}")Things to watch
- Venues often list different numbers of outcomes. Show unmatched ones separately rather than dropping them silently.
- Skip or grey out quotes whose
freshnessisstaleorunknown. comparison: "comparable"means the venues ask a similar but not identical question. Show theresolution.summaryand each market'srules(from/markets/{venue}/{market_id}).- A positive
gapis gross: before fees and depth. It is a lead, not a guaranteed profit.
Related
Build with TPM
Get your free API key
One key gives you Kalshi and Polymarket events, prices with freshness, price history, cross-venue gaps and the live quotes WebSocket.