Skip to main content
A crypto market is a binary market whose question is about the price of a digital asset rather than a sporting or political outcome. It trades, settles and redeems exactly like any other binary market — same orderbook, same EIP-712 order, same ConditionalTokens redemption — but the payload carries an extra machine-readable block so you never have to parse the market title or the rules text. Two product lines exist today:

Long-dated price markets

Operator-listed yes / no questions — “will BTC touch 64,400before30July?","willtheJulyclosebeabove64,400 before 30 July?", "will the July close be above 65,000?”. Lifetimes of days to months, listed one-off or as a recurring series of daily / weekly / monthly periods. Described on this page.

Up/Down windows

Machine-minted Up / Down markets on a recurring 15-minute (or hourly / daily) grid, grouped into a series. Their own page — they add a cryptoWindow block and a series navigation endpoint.
Both lines carry the same crypto block, the same instrument catalog and the same live price feed, so a client that renders one renders the other with one extra null-check.

Finding crypto markets

Crypto markets live under the crypto vertical. The event list takes the filter directly:
All four accept repeated keys (?asset=btc&asset=eth) or CSV (?asset=btc,eth), up to 20 distinct values per field. GET /api/verticals returns the counts behind those chips — on the crypto vertical only, the summary carries an extra crypto block:
Each bucket is an independent overlap count (one event can sit in several) — never derive one from another, or from count. frequencies, cadences and assets map 1:1 onto ?frequency= / ?cadence= / ?asset=, and preMarket onto ?vertical=crypto&preMarket=true (the preMarket filter is platform-wide, so keep the vertical). Array chips are emitted only when count > 0; preMarket and others are fixed fields that are always present, with all three numbers at 0 when empty — render them only when count > 0. A bucket’s openMarketCount / totalMarketCount count its own markets (the open view / including closed ones), not every market of its events.

The crypto block

Every market payload — /api/markets, /api/markets/{slug}, and the nested markets[] on /api/events — carries a crypto field. It is null on every non-crypto market, and on a crypto market it is the structured counterpart of the human resolutionCriteria text:
title carries the strike. On a crypto market with a targetPrice, the market title is the bare strike digits ("64400") — the surrounding copy lives on the parent event. Format the number yourself (thousands separators, currency); don’t string-parse the rule out of the title.
Branch on crypto, not on marketType. Crypto markets carry marketType: "CRYPTO_PRICE_EVENT", but some older ones — Up/Down windows in particular — carry null, and the value can’t tell a window from a long-dated market anyway. The reliable discriminators are crypto !== null (any crypto market) and cryptoWindow !== null (Up/Down window specifically).

Product catalog

The productType values in use. Every product except UP_DOWN_WINDOW is listed by an operator — one market at a time, or each period from a recurring series the operator has set up; Up/Down windows are minted automatically, one market per series window. Calendar months run midnight to midnight US Eastern time. A “period” product’s window is not in the crypto block — read it from resolutionCriteria, which GET /api/events list rows keep on long-dated markets. Touch products (THRESHOLD_*) settle on a first touch: equality counts, and the YES outcome locks the moment the barrier is touched, even though the market settles after the observation window ends.

Long-dated series

A long-dated market is listed either one-off or as part of a recurring series that lists one event per period — daily, weekly or monthly. An event that belongs to a series carries a cryptoLongSeries block; every other event carries null:
On the default (open) GET /api/events view a series appears as one event, with its sibling periods in periods[]; the closed view (?status=closed) lists every settled period as its own event.
The response is { "periods": [ … ], "hasMore": false } — entries of the same shape as cryptoLongSeries.periods[], most recent start first. An unknown series id returns an empty list. Invalid parameters return 400 with invalid_state, invalid_limit, invalid_offset, invalid_from or invalid_to. Public endpoint, 600 req/min per IP, Cache-Control: public, max-age=5.

Instruments

Spot prices are sourced from Chainlink — one-minute candlestick data for long-dated products, Data Streams reports for the Up/Down open pin. Dominance, market-cap and rank products resolve from CoinGecko data. The crypto-price-history endpoint below serves BTC-USD, ETH-USD, BTC-DOM, TOTAL-MCAP and SOL-RANK; any other instrument → 422 instrument_unsupported.

Underlying price curve

The probability charts (/ohlc, /price-history) describe the market. This endpoint describes the coin — the reference price the market is written against:
Path parameter is the market symbol (like the other market sub-resources — only the root /api/markets/{slug} detail takes a slug). range is required: 1m is the month preset; the one-minute view is 1min. 1min and 10m are built from recorded live price ticks, with finalized one-minute candles filling any stretch the ticks don’t cover — so a 1min request with no tick coverage usually returns points: [] with a non-null spot. Every other preset uses the finalized one-minute candles. The range normally ends now; on a closed Up/Down window it ends at the window’s own end instead, so a settled window charts itself — read the echoed from / to. Buckets with no source data are absent, not zero-filled — a 1h request typically returns 57–60 points. Draw gaps, don’t interpolate across them.
  • points[] are per-bucket closes in ascending time order, already scaled to human decimal strings. Only complete, grid-aligned buckets are returned, so the series is stable between polls — from / to echo the snapped window the server actually queried. The one exception is a closed Up/Down window, whose last bucket ends at the window end and may be partial.
  • spot is the newest observation for the instrument — the latest live tick on 1min / 10m, otherwise the latest finalized minute — and may sit past to; null when none exists yet.
  • priceToBeat is the reference line to draw on the same axis — the frozen open of an Up/Down window, already scaled. It is null on long-dated markets: their reference line is crypto.targetPrice.
Public endpoint — no auth required. Two IP buckets apply together: the shared markets ceiling (600 req/min) and this route’s own (240 req/min). Successful responses carry Cache-Control: public, max-age=<n> with the per-preset value from the table above; error responses carry no-store.
For a live price, don’t poll this endpoint — subscribe to crypto_price_tick and append ticks to the curve you fetched. One feed per instrument serves every strike and every window on that asset.

Settlement

Crypto markets settle through the standard binary path — oracle proposes, challenge window, finalize, redeem — see Settlement flow. The difference is the evidence: the outcome is derived from Chainlink price data (CoinGecko data for dominance, market-cap and rank products) against the immutable rule captured in the crypto block at listing time, not from a sports data provider. The rule is written once and never edited, so crypto on an open market is the same rule the settlement engine will bind.