Markets and history
Every listed market on Kalshi and Polymarket with its rules, result and price history, and the venues' settled record by speaker and phrase.
On this page
Every market, public
GET /v1/public/markets is the index of every Kalshi and Polymarket market Langbot lists. It needs no token.
| Param | Meaning |
|---|---|
q | free text over ticker and title |
venue | kalshi or polymarket |
status | open, settled or all (default) |
category | a category slug; the response lists the categories |
sort | volume (default), or by closing time or newest |
limit, cursor | page size; next_cursor from the previous page |
Each row carries ticker, venue, title, status, result, price and volume. Kalshi combination markets are left out unless you search for them.
GET /v1/public/markets/{ticker} is one market's public page:
series.points: the price history as[ms epoch, YES price]pairs;series.sourceisorderbook_midwhen the prices come from the order book Langbot recorded, otherwise the venue's own prices;resultandoutcomeonce the market has settled;sim.has_books: whether the simulator can replay the event behind it.
langbot markets "house control" --venue polymarket
langbot market KXEARNINGSMENTIONGS-26OCT13-PRIVimport asyncio
from langbot import LangbotClient
async def main():
async with LangbotClient() as lb:
m = await lb.public_market("KXEARNINGSMENTIONGS-26OCT13-PRIV")
print(m["status"], m["result"], m["series"]["source"], m["sim"]["has_books"])
asyncio.run(main())import { LangbotClient } from "@langbotai/sdk";
const m = await new LangbotClient().publicMarket("KXEARNINGSMENTIONGS-26OCT13-PRIV");
console.log(m.status, m.result);For a finer price history, GET /v1/history/candles?ticker=&period=1m|1h|1d&since=&until= returns candles oldest first, paged by next_since (a token; one history query).
The same question often trades on both venues. The consolidated price puts the equivalent markets together into one number, with its method.
The settled record
Every market that has settled is a public fact: the venue published its rules, its open and close prices and its result. Langbot keeps those facts in one table, keyed by the speaker and the phrase the market was about (for markets on what someone says), with a canonical speaker key so "Chair Powell", "Powell" and "the Chair" are one speaker.
It is the venue's record, not Langbot's reading of it.
{
"ticker": "KXFEDMENTION-26SEP-TRANSITORY",
"venue": "kalshi",
"series_ticker": "KXFEDMENTION",
"title": "Powell says “transitory”?",
"speaker": "powell",
"phrase": "transitory",
"event_id": "ev_fomc_sep_2026_presser",
"result": "no",
"open_ts": 1757980800000,
"close_ts": 1758654000000,
"settled_ts": 1758661200000,
"yes_price_open": 18,
"yes_price_close": 2,
"volume": 41250
}result is yes, no or void. Prices are in cents. event_id is set when the market maps to an event Langbot recorded, which joins outcomes to Langbot's own phrase hits.
| Endpoint | Returns |
|---|---|
GET /v1/history/outcomes?speaker=&phrase=&series=&venue=&since=&until=&limit=&cursor= | settled rows, newest first; limit up to 500; pass next_cursor back as cursor |
GET /v1/history/base-rates?speaker=&phrase=&series=&window_days=365 | counts and the YES rate for a speaker, a phrase or the pair |
GET /v1/history/speakers?q= | speaker profiles with their market counts |
GET /v1/history/mentions?speaker=&phrase=&since=&until=&limit= | Langbot's own phrase hits: phrase, speaker, event, timestamps, tickers. Never the surrounding text |
GET /v1/calendar?days=7 | upcoming and live events with sources, markets, speakers and rights (public) |
GET /v1/context/{ticker} | one market with its rules, latest book, base rate for its speaker and phrase, its event and recent mentions |
The history endpoints take a token (each call is one history query of your plan's daily allowance) or a per-call payment. Every plan sees the full record.
Base rates
For a speaker and phrase inside the window:
marketscounts every settled row;yes,noandvoidsplit it.yes_rate = yes / (yes + no); voids are left out of the denominator.by_monthbuckets rows by settlement month (UTC) with the same rate.avg_open_priceandavg_close_priceaverage the opening and closing YES prices in cents.mispricingis the average of (1 if the market settled YES, else 0) minus the opening YES price as a fraction, over non-void rows: how far opening prices sat from results on the record.
Omit phrase for a speaker-wide rate, or speaker for a phrase-wide rate. These numbers summarise what has settled and at what price. They are a description of the past, not a forecast for the next market, and what you do with them is your decision.
langbot rates --speaker powell --phrase transitory
langbot outcomes --speaker powell --phrase transitory
langbot context KXFEDMENTION-26OCT-TRANSITORYimport asyncio
from langbot import LangbotClient
async def main():
async with LangbotClient() as lb:
rates = await lb.base_rates(speaker="powell", phrase="transitory", window_days=365)
print(rates.markets, rates.yes_rate)
page = await lb.outcomes(speaker="powell", phrase="transitory")
for o in page.items:
print(o.ticker, o.result, o.yes_price_open, o.yes_price_close)
asyncio.run(main())import { LangbotClient } from "@langbotai/sdk";
const lb = new LangbotClient();
const rates = await lb.baseRates({ speaker: "powell", phrase: "transitory" });
const page = await lb.outcomes({ speaker: "powell", phrase: "transitory", limit: 50 });
console.log(rates.yes_rate, page.items.length);get_base_rates, search_outcomes, search_mentions, list_speakers, get_calendar and get_market_context return the same data to your agent. See Connect your agent.
Calibration
langbot research calibration (and GET /v1/research/calibration) compares opening prices with results over every settled market the filters keep, by price bucket, with a 90% interval, a Brier score and the caveats. See Simulator and backtesting.