Skip to main content
PredictStreet groups one or more markets under an Event. A single match (Real Madrid vs Manchester City) typically maps to one event with one binary market. A tournament (UEFA Champions League winner) maps to one event with many per-team markets shown as a Polymarket-style accordion via groupItemTitle. Every event response carries the event’s markets in markets[], but not always the same market row: the list (GET /api/events) carries a slimmer list row per market, while GET /api/events/{slug} and GET /api/events/featured carry the full MarketSummaryDto — see List rows vs detail. Most clients query GET /api/events for the home grid, GET /api/events/{slug} for an event page and GET /api/markets/{slug} for the trading detail page.

Event shape

One row of GET /api/events (the event fields are the same on GET /api/events/{slug} and GET /api/events/featured). Every event-level key is always present; nullable ones are null, never missing. For the keys of each markets[] row, see List rows vs detail.

Football metadata fields

Other event fields

Crypto events

An event in the crypto vertical carries a cryptoSeries block when its markets belong to a recurring Up/Down series; every other event carries null. The factory creates one event per series per UTC day, so an Up/Down event is a day of windows (~96 at the 15-minute cadence) — navigate it through GET /api/crypto-series/{id}/windows rather than through markets[], which nests only the windows around now: the tradeable ones on the list, plus the windows awaiting settlement and the three latest-ending settled (RESOLVED or VOIDED) windows on GET /api/events/{slug}. A finished day on the list’s ?status=closed view nests the same: every window still awaiting settlement and at most three settled ones. The one exception is a day whose windows were all VOIDED before they ended: the list nests all of them, and GET /api/events/{slug} returns 404 for it. For the whole day, settled windows included, call GET /api/crypto-series/{id}/windows?state=all&from=2026-07-29&to=2026-07-30. totalMarketCount counts every window of the day. Check each market’s status before trading.
Long-dated crypto events (price thresholds, monthly closes) have cryptoSeries: null — their markets carry the rule in crypto, and an event that is one period of a recurring long-dated series carries a cryptoLongSeries block.

Per-market fields driven by the event grouping

List rows vs detail

The event fields are the same on all three. Because markets[] depends on the view, render counts from openMarketCount / totalMarketCount, never from markets.length. The order of markets[] is stable but not part of the contract.

Fields the list row leaves out

Slimmer list rows. A market row on GET /api/events is the full MarketSummaryDto without the fields below. Everything else — ids and token ids, outcomes, outcomePrices, chances, status, tradable, tradingWindow, lifecycle, resolution, crypto, cryptoWindow, marketType, vertical, volumes — is the same as on the full row. Migration notes: Changelog.
Two blocks are trimmed rather than removed:
  • prediction is null except on markets listed from a vendor prediction question (for example politics).
  • probabilityChange is the 24-hour move of each outcome’s implied probability, in percentage points (0.27 → 0.32 is 5), rounded to two decimals. change is null when there is no price to compare with; the block itself can be null or absent.
For full rows in bulk, page GET /api/markets?limit=500&offset=… (up to 500 full rows per request, with hasMore; PRE_MARKET, OPEN, PAUSED and POSTPONED by default, closed=true or status= for the others) instead of calling GET /api/events/{slug} once per event — detail calls share the /api/events* rate-limit bucket with your list walk. For one event’s markets in any status, call GET /api/events/{slug}; for one market, GET /api/markets/{slug} (no probabilityChange).

Filtering

Filters AND across fields and OR within a field. The multi-value fields (stage, group, team, tag, vertical, competition, subcategory, scope, asset, cadence, frequency, predictionType) accept repeated keys (?tag=a&tag=b) or CSV (?tag=a,b) — both forms can be mixed, up to 20 distinct values per field, duplicates collapsed. More is 400 too_many_<field>, for example too_many_tag (predictionType uses too_many_prediction_type). By default the list holds events with at least one tradeable market (PRE_MARKET / OPEN / PAUSED / POSTPONED), plus fixtures currently in play, whose markets may already be CLOSED. ?status=closed (or the legacy ?closed=true) returns the settled / finished set instead: events with no tradeable market and at least one closed market, excluding fixtures in play.

Paging

GET /api/events returns at most 100 events per response. Page with page / limit: a limit above 100 is served as 100, not rejected, and without page / limit you get the first 100 events. Walk page=1, 2, … with limit=100 and stop at the first empty page. The first page (page=1, from=0, or no page and no digits-only from) also carries total, the number of events matching every filter, independent of paging, and openMarketCount / totalMarketCount, the per-event counters summed over those events — so on status=closed the open sum is 0; show totalMarketCount. With scope, both hold the same number instead: the markets of those scopes that the filter admits on the view, not the sum of the rows’ counters. Later pages carry none of the three unless the request has q. Treat them as optional: when they cannot be computed in time, the first page comes without them. Full rules, including the numeric from / to positions: Pagination.
List data can be up to a minute or two old. Which events a page holds, their order, volumes and each market’s status / tradable come from a list slice shared by every caller that can be up to about 20 seconds old. Anonymous requests — API-key requests included, since the key is ignored on this endpoint — are then served from a short cache on top: usually a few seconds, up to about 30 seconds for a full page of 100 events, 60 seconds for a full status=closed page, and 2 minutes on a closed page where every market is settled. A first page’s total, openMarketCount and totalMarketCount are cached with it. Do not use GET /api/events as a price feed; read the orderbook or the WebSocket instead.

Tags

The tag taxonomy is admin-curated rather than free-form. Use GET /api/tags for the full active list and the slug as the value for ?tag=.
isFeatured tags are surfaced in the primary navigation strip; non-featured tags remain selectable through filter UI but are not pinned.