Prediction Market Event Reference Data
Overview
Prediction market event reference data describes every prediction market event that Coin Metrics collects from Kalshi and Polymarket. An event is the question a venue lists, such as "Fed decision in Dec 2027?", and it groups one or more tradable markets, each a Yes or No contract on one outcome or variant of that question. For each event the data provides its title and description, the recurring series it belongs to, its category and tags, its lifecycle status and close time, and whether its markets are mutually exclusive. It is used to discover and classify prediction markets, to group individual markets under the question they answer, and to build the list of markets to query for trades, candles, and open interest.
At a Glance
| Data type | Entities | Frequency / cadence | Unit | Primary endpoint |
|---|---|---|---|---|
| Prediction market event reference data | Prediction market events (Kalshi, Polymarket) | Reference data, refreshed on an ongoing basis as venues change | Not applicable (descriptive metadata) | /reference-data/events |
Schema
The response returns one object per event. Every event carries the four identification fields. The remaining fields are populated only where the venue provides them, so Kalshi and Polymarket events each return a different subset of the schema below. Fields without a value are omitted from the response.
Identification (all events)
| Field | Type | Description | Notes |
|---|---|---|---|
event | string | Globally unique Coin Metrics identifier for the event, of the form <exchange>-<event_ticker>. See Event identifiers. | Required |
exchange | string | Coin Metrics identifier for the venue that defines the event. Currently kalshi or polymarket. | Required |
event_ticker | string | Event identifier exactly as reported by the venue: the event ticker on Kalshi, the event slug on Polymarket. | Required |
last_updated_time | string (date-time) | Time at which Coin Metrics last observed a change to this event's metadata. See Change tracking. | Required |
Description and classification
| Field | Type | Description | Notes |
|---|---|---|---|
title | string | Primary human-readable title of the event. | All venues |
subtitle | string | Secondary human-readable title supplied by the venue. | Kalshi |
description | string | Long-form description of the event supplied by the venue, typically including its resolution rules. | Polymarket |
category | string | Broad subject category assigned to the event by the venue. | Kalshi, Polymarket (rarely) |
subcategory | string | More specific venue-provided classification within the category. | Polymarket (rarely) |
tags | array[object] | Venue-provided labels used to classify, group, or discover the event, passed through verbatim from the venue. Each tag carries at least an id, a slug, and a label. | Polymarket |
Series
| Field | Type | Description | Notes |
|---|---|---|---|
series_ticker | string | Venue-native identifier of the recurring series or collection the event belongs to. | All venues |
series_title | string | Human-readable title of the series. | All venues |
series_frequency | string | Venue-provided recurrence frequency of the series, for example daily, weekly, or custom. Values are venue-specific. | All venues |
Lifecycle
| Field | Type | Description | Notes |
|---|---|---|---|
status | string | Lifecycle status of the event. active, inactive, or closed on Kalshi, and active, closed, or archived on Polymarket. See Status and close time. | All venues |
created_time | string (date-time) | Time at which the venue created the event. | Polymarket |
close_time | string (date-time) | Time at which the event closes, or closed. Determines whether the event is live. See Status and close time. | All venues |
Outcome structure and venue terms
| Field | Type | Description | Notes |
|---|---|---|---|
mutually_exclusive | boolean | Whether the event's markets represent mutually exclusive outcomes. See Mutually exclusive outcomes and negative risk. | Kalshi (true or false), Polymarket (true only) |
neg_risk_enabled | boolean | Polymarket flag indicating that the event uses the negative-risk mechanism. | Polymarket |
neg_risk_augmented | boolean | Polymarket flag indicating that the negative-risk event supports adding outcomes after creation. | Polymarket |
strike_date | string (date-time) | Date and time used by the event's strike definition. | Kalshi |
strike_period | string | Time period used by the event's strike definition, for events defined over a period rather than a date. | Kalshi (rarely) |
collateral_return_type | string | Venue-reported treatment of collateral returns for the event, for example MECNET or DIRECNET. | Kalshi |
Conventions. Timestamps (last_updated_time, created_time, close_time, and strike_date) are UTC ISO-8601 with nanosecond resolution. Fields without a value are omitted rather than returned as null. Text and classification values (status, category, series_frequency, and the contents of tags) are passed through in each venue's own vocabulary and are not harmonized across venues. Objects inside tags keep the venue's own field names and timestamp formats.
Methodology
Collection
Coin Metrics collects event metadata directly from the public API of each supported prediction market venue, currently Kalshi and Polymarket. Each venue is polled about every five minutes. Every poll picks up events that were created or changed since the previous one and also advances a slower crawl through the venue's full catalog, so that older and already settled events are backfilled over time. Events and their markets are collected in the same pass, which keeps this endpoint consistent with the prediction markets served by /reference-data/markets. Records are never deleted: closed, settled, and archived events remain available with include_expired=true.
On Kalshi, category is taken from the event and falls back to the category of its series, while series_title and series_frequency are attached from the venue's series catalog. On Polymarket, the series fields come from the first series the venue lists on the event. Kalshi multivariate (combination) events, which bundle markets from several other events, are not collected.
Event identifiers
Every event is identified by event, built as <exchange>-<event_ticker>. The event_ticker keeps the venue's own identifier verbatim: the event ticker on Kalshi (for example KXFEDDECISION-27DEC) and the event slug on Polymarket (for example largest-company-end-of-december-2026). Tickers are case-sensitive and are matched exactly, while the exchange prefix is not case-sensitive. Because a ticker can itself contain hyphens, split an event value on its first hyphen only. The same identifier appears in the event field of each prediction market in /reference-data/markets, which is how events and markets join.
Status and close time
The status and close_time fields come from the venue where it provides them, and are otherwise derived from the event's markets.
- Polymarket.
statusisarchivedif the venue has archived the event,closedif the venue has closed it, andactiveotherwise. Once the event has closed,close_timeis the time the venue closed it. While it is open,close_timeis the latest close or scheduled end among its markets. - Kalshi. The venue does not report an event-level status or close time, so both are derived from the event's markets. An event is
activeif at least one of its markets is open for trading,inactiveif none is open but at least one has not yet closed (for example a market that has not opened yet), andclosedonce every market has closed (or when none of its markets has been collected).close_timeis the latest scheduled close among its markets, falling back to their latest possible expiration.
Derived values are recomputed each time the event itself is collected again, so they can briefly trail a change to one of its markets.
Liveness and expired events
An event is live while its close_time is in the future. A request that lists all events, or filters by exchange, returns only live events by default. Set include_expired=true to also return events whose close_time has passed or is unknown. A request that names specific events with events or event_tickers returns them whatever their status, so a closed event can always be looked up by its identifier.
Markets apply the same idea to their own expiration in /reference-data/markets (see Liveness and expired markets). Because events and markets use different timestamps, they do not always agree. Kalshi markets, for example, stay in the default market listing for about a week after they settle, so the markets of a closed event can still appear there.
Liveness also does not follow status. An event whose close_time has passed drops out of the default listing even while its status is still active. This is common on Polymarket, where an event can stay active after its scheduled end while it awaits resolution.
Mutually exclusive outcomes and negative risk
An event groups one or more binary markets. The mutually_exclusive field records whether those markets are alternatives of which only one can resolve Yes, such as the possible outcomes of a single rate decision. On Kalshi the venue reports the value as true or false. On Polymarket it is derived from the venue's negative-risk designation, which Polymarket applies to events whose markets are mutually exclusive. It is true for those events and omitted otherwise, so its absence on a Polymarket event does not mean the outcomes overlap.
The neg_risk_enabled and neg_risk_augmented fields pass through Polymarket's own flags. The first marks events set up for the negative-risk mechanism. The second marks events to which new outcomes can be added after creation (for example a new candidate entering a race).
Change tracking
The last_updated_time field is the time Coin Metrics last observed a change to any of the event's stored fields. It is not the venue's own update time. Collecting an event again without a change leaves it untouched, so comparing last_updated_time across two pulls shows which events changed in between. A known created_time is never overwritten by an empty value on a later collection.
Accessing the Data
Prediction market event metadata is served by the /reference-data/events endpoint. Requests are filtered by one of events (Coin Metrics event identifiers), exchange (kalshi or polymarket), or event_tickers (venue-native tickers, matched across all venues). Only one of the three can be used per request. Add include_expired=true to an unfiltered or exchange request to include expired events. Results are limited to the venues your API key has access to: naming a venue your key does not cover returns an error, while an unfiltered request simply omits it.
Python Client
from coinmetrics.api_client import CoinMetricsClient
client = CoinMetricsClient("YOUR_API_KEY")
# Metadata for specific events, live or expired
events = client.reference_data_events(
events=["kalshi-KXFEDDECISION-27DEC", "polymarket-largest-company-end-of-december-2026"],
).to_dataframe()
print(events)
# All live events on a venue
kalshi = client.reference_data_events(exchange="kalshi").to_dataframe()
# Events by venue-native ticker or slug, matched across venues
fed = client.reference_data_events(event_tickers=["KXFEDDECISION-27DEC"]).to_dataframe()
Shell
curl --compressed "https://api.coinmetrics.io/v4/reference-data/events?events=kalshi-KXFEDDECISION-27DEC,polymarket-largest-company-end-of-december-2026&page_size=10000&api_key=$CM_API_KEY"
Python
import os
import requests
response = requests.get(
"https://api.coinmetrics.io/v4/reference-data/events",
params={
"events": "kalshi-KXFEDDECISION-27DEC,polymarket-largest-company-end-of-december-2026",
"page_size": 10000,
"api_key": os.environ["CM_API_KEY"],
},
).json()
Results are ordered by exchange, then by event ticker. Responses are paginated: the Python client follows pagination automatically, while direct HTTP callers page through results using next_page_token. The default listing holds only live events, which keeps it to tens of thousands of events per venue, while include_expired=true returns a venue's full history of hundreds of thousands. For a full pull of a venue, format=json_stream returns every matching event in a single streamed response without paging. Full parameter reference: see the API Reference for /reference-data/events.
Examples
Example: Kalshi event
A live Kalshi event for a Federal Reserve rate decision. Its markets are mutually exclusive (one per possible decision), and the venue-specific subtitle, strike_date, and collateral_return_type fields are populated. Run this query.
{
"data": [
{
"event": "kalshi-KXFEDDECISION-27DEC",
"exchange": "kalshi",
"event_ticker": "KXFEDDECISION-27DEC",
"last_updated_time": "2026-09-30T10:21:55.614640000Z",
"title": "Fed decision in Dec 2027?",
"subtitle": "On Dec 8, 2027",
"category": "Economics",
"series_ticker": "KXFEDDECISION",
"series_title": "Fed meeting",
"series_frequency": "custom",
"mutually_exclusive": true,
"status": "active",
"close_time": "2027-12-08T18:59:00.000000000Z",
"strike_date": "2027-12-08T19:00:00.000000000Z",
"collateral_return_type": "MECNET"
}
]
}
Example: Polymarket event
A live Polymarket event that belongs to a monthly series. Polymarket events carry a description with the resolution rules, a created_time, the negative-risk flags, and venue tags (truncated here to two of six). Run this query.
{
"data": [
{
"event": "polymarket-largest-company-end-of-december-2026",
"exchange": "polymarket",
"event_ticker": "largest-company-end-of-december-2026",
"last_updated_time": "2026-09-30T10:12:30.693328000Z",
"title": "Largest Company end of December 2026?",
"description": "This market will resolve to the largest company in the world by market cap on December 31, 2026, as of market close.\n\nThe resolution source for this market will be a consensus of credible reporting.",
"series_ticker": "largest-company",
"series_title": "Largest Company",
"series_frequency": "monthly",
"mutually_exclusive": true,
"status": "active",
"created_time": "2025-11-12T21:22:24.034798000Z",
"close_time": "2027-01-01T04:59:00.000000000Z",
"neg_risk_enabled": true,
"neg_risk_augmented": true,
"tags": [
{
"id": "100328",
"slug": "economy",
"label": "Economy",
"createdAt": "2024-08-05T05:34:54.235643Z",
"forceShow": false,
"updatedAt": "2026-04-17T20:29:06.948273Z"
},
{
"id": "107",
"slug": "business",
"label": "Business",
"createdAt": "2023-11-02T21:20:37.488Z",
"forceShow": false,
"updatedAt": "2026-04-17T20:26:28.786983Z",
"publishedAt": "2023-11-02 21:20:37.48+00"
}
]
}
]
}
Example: closed event looked up by identifier
A Kalshi event that has already closed. Because it is requested by its identifier, it is returned without include_expired=true. Run this query.
{
"data": [
{
"event": "kalshi-APPLEFOLD",
"exchange": "kalshi",
"event_ticker": "APPLEFOLD",
"last_updated_time": "2026-09-30T10:21:28.247377000Z",
"title": "When will Apple announce foldable iPhone?",
"subtitle": "Announcement",
"category": "Financials",
"series_ticker": "KXAPPLEFOLD",
"series_title": "Apple reveals foldable iPhone",
"series_frequency": "custom",
"mutually_exclusive": false,
"status": "closed",
"close_time": "2026-09-09T18:32:35.000000000Z"
}
]
}
Usage
The standard workflow is to find the events you care about here, resolve them to their markets, and then pull market data for those markets.
- Discover events. Query
/reference-data/eventsbyexchangeto list live events, and addinclude_expired=truefor history. Classify them withcategory,tags, orseries_ticker, which groups recurring events such as each scheduled rate decision. - Resolve events to markets. Query
/reference-data/marketswithtype=event_contractand the sameexchange, and keep the markets whoseeventfield matches (see Joining markets to events). The Kalshi eventkalshi-KXFEDDECISION-27DEC, for example, resolves to five markets such askalshi-KXFEDDECISION-27DEC-H25-event_contract, one per possible decision. A venue's live market listing runs to hundreds of thousands of markets, and on Kalshi most of them have already settled (see Liveness and expired markets), so useformat=json_streamfor this pull. Addinclude_expired=trueonly when you need the markets of closed events, because it extends the pull to the venue's full history of millions of markets. - Pull market data. Check the time range available for those markets with
/catalog-v2/market-trades(an explicitmarketslist needs notype), then call/timeseries/market-trades,/timeseries/market-candles, or/timeseries/market-openinterestwith the market list andtype=event_contract. The timeseries endpoints reject prediction markets whentype=event_contractis missing.
The event metadata also shapes how the market data is read. When mutually_exclusive is true, the event's markets are alternative answers to one question, so their prices can be read together as probabilities across those alternatives. When it is false, the markets are separate Yes or No questions whose outcomes can overlap.
Limitations
- Field availability varies by venue. Each venue exposes a different set of fields, and fields a venue does not provide are omitted. Polymarket rarely populates
category, so usetagsto classify Polymarket events. - Vocabularies are not harmonized. Values of
status,category, andseries_frequencyare venue-specific, for examplefifteen_minon Kalshi and15mon Polymarket for the same recurrence. - Derived status and close time can lag. Kalshi
statusandclose_time, and Polymarketclose_timefor open events, are derived from the event's markets and are refreshed when the event itself is collected again. statusand liveness can disagree. An event can still reportactiveafter itsclose_timehas passed, either because the venue has not yet closed it (typically while it awaits resolution) or because its derived status has not been refreshed. Such events are excluded from default listings and needinclude_expired=true.- Events without a close time are treated as expired. An event whose
close_timeis unknown is not returned by default and needsinclude_expired=trueor an expliciteventsorevent_tickersfilter. - Series metadata can be missing. A small share of Kalshi events have no
series_titleorseries_frequency, and Polymarket events that belong to more than one series report only the first. - Multivariate events are excluded. Kalshi multivariate (combination) events are not collected.
- No market filter by event.
/reference-data/marketshas no parameter to select the markets of one event, so resolving an event to its markets means filtering a venue's markets on theeventfield.
FAQ
Why doesn't an event appear when I list a venue's events?
By default, a listing returns only live events, meaning events whose close_time is in the future. Events that have closed, or whose close time is unknown, are returned when you add include_expired=true, or when you request them directly with events or event_tickers.
Is status comparable across Kalshi and Polymarket?
Only at a coarse level. Both venues use active for an event that is open and closed for one that has closed. Kalshi adds inactive for an event none of whose markets is open for trading although some have not closed, and Polymarket adds archived. For a single cross-venue test of whether an event is still open, compare close_time with the current time, which is the rule the endpoint itself uses for liveness. The two signals can disagree, because an event can stay active for a while after its close_time passes.
Related
- Market Reference Data: metadata for every market, including the prediction markets (
type=event_contract) that belong to these events. - Market Trades: tick-level trade data, including prediction market trades.
- Market Candles: OHLCV candles, including prediction market candles.
- Market Open Interest: open interest, including prediction market open interest.