GuidesCookbook
Screen markets across every venue
One request returns at most 100 markets. Screening the catalog means paginating, and doing it with the cursor rather than with a page count.
router searches every venue at once; a venue id scopes it to one.
curl -s "$PREDICTEFY_API_URL/api/router/fetchMarkets?query=election&status=active&limit=100&sort=volume" \ -H "Authorization: Bearer pk_live_YOUR_KEY"The parameters that matter for screening:
| Parameter | Values |
|---|---|
status | active, inactive, closed, resolved, all |
sort | volume, liquidity, newest |
limit | 1–100 |
searchIn | title, description, both |
searchMode | lexical (default), semantic, hybrid |
searchMode is worth knowing: the default is a literal match. semantic ranks the venue’s
markets by title meaning (voyage-3.5 vectors). Results are limited to markets whose titles have
been embedded — the catalog embedding pass runs with the matcher (hourly), so brand-new markets
can lag; total is the number of matches within the scan window. hybrid combines that ranking
with lexical search.
async function screen({ query, status = 'active', limit = 100, maxPages = 20, venue = 'router' }) { const out = []; let cursor = null; let pages = 0;
do { const url = new URL(`/api/${venue}/fetchMarkets`, BASE); url.searchParams.set('status', status); url.searchParams.set('limit', String(limit)); if (query) url.searchParams.set('query', query); if (cursor) url.searchParams.set('cursor', cursor);
const res = await fetch(url, { headers: { Authorization: `Bearer ${process.env.PREDICTEFY_API_KEY}` }, }); const body = await res.json(); if (!body.success) { // A cursor older than its TTL comes back as VALIDATION_ERROR. Restart the sweep. throw new Error(`${body.error.code}: ${body.error.message}`); }
out.push(...body.data); cursor = body.page?.hasMore ? body.page.nextCursor : null; pages += 1; } while (cursor && pages < maxPages);
return out;}Filtering on the normalized record
Section titled “Filtering on the normalized record”Every market comes back in the same shape whichever venue served it. The fields worth screening on:
| Field | Note |
|---|---|
sourceExchange | The venue that served this row — not venue |
volume / volume24h | All-time and rolling; volume24h is nullable |
liquidity | Nullable |
status | Matches the filter vocabulary above |
category / tags | The venue’s own vocabulary |
canonicalCategory / canonicalTags | Predictefy’s cross-venue vocabulary, both nullable |
outcomes | The sides you can hold; books key on these |
outcomes[].priceChange* | Eight windows: 1m, 5m, 15m, 1h, 6h, 24h, 7d, 30d |
outcomes[].coverage | Tape coverage mechanism, interval, and 24h gap metrics |
asOf / provenance / capabilities | Required on every record — see below |
Market and event images
Section titled “Market and event images”Every unified market carries four image fields. Image URLs are venue-hosted or Predictefy-hosted strings, passed through without a proxy or CDN:
image: the venue’s own art for the market. It follows this order: the market’s image, then a Kalshi market’s series art, then its parent event’s image. It isnullwhen the venue publishes none of those.eventImage: the parent event’s art alone. It isnullwhen there is none.imageResolvedandimageSource: the picture to show and where it came from.imageSourceisvenuewhenimageResolvedis the venue’s own art (the URLimageheld when the image stage last ran). The valuesleague,team,siblingandcategoryname substitutes Predictefy stored for a market whose venue publishes no art.leagueandteamare the fixture’s competition image and a team logo from Predictefy’s sports catalog, attached through the market’s fixture key. These values appear once the sports catalog holds that art; until then, sports markets without venue art fall through tosiblingorcategory.siblingis another venue’s newest venue-art market in the same cluster;categoryis a canonical-category placeholder (/img/categories/<slug>.svg). Both fields arenulluntil Predictefy’s image stage has looked at the market, and staynullwhen it finds no picture.imageSourceis never set withoutimageResolved. The source valuesseriesandeventare reserved.outcomes[].image: venue-stated art for one outcome, such as team logos on Polymarket, Polymarket US and Pred sports legs. It is present only when the venue states one.
For a thumbnail, select market.imageResolved ?? market.image ?? market.eventImage;
if all three are null, use your own placeholder.
To prefer the venue’s newest art, use market.image ?? market.imageResolved ?? market.eventImage;
both thumbnail orders agree whenever the pair is current.
When enabled, the image stage resolves open, active markets once per matcher run. Closed, inactive and resolved markets keep the pair from their last pass while open and active. They have no pair if they left that scope before the stage first saw them.
The image stage writes imageResolved, while ingest writes image on a separate schedule,
so imageResolved can be older than image. A substitute is chosen only while the venue’s
image is empty. When venue art arrives later, ingest exposes it in image immediately.
If the market remains in scope, the next image pass replaces the substitute.
A null imageSource means no resolved picture is available. The market may not be resolved yet,
the stage may have found no picture, or the market may be outside its scope. It does not mean the venue has
no art: venue art can still be present in image and eventImage.
To show only the venue’s own art, skip the resolved pair and use
market.image ?? market.eventImage. To accept only some sources, use imageResolved
when imageSource is in your list; otherwise use market.image ?? market.eventImage.
Each market stores at most one resolved picture, chosen in the order venue, league, team,
sibling, category. A market resolved to a source outside your list has no category
placeholder to fall back to. If image and eventImage are also null, use your own
placeholder.
league, team and sibling are art derived from another source; each is only as right
as the fixture key or cluster behind it.
Market-level art is available from Polymarket, Polymarket US, PredictStreet,
PredictFun, Limitless, Myriad, XO and Rain, though individual markets may have none.
Polymarket also publishes parent-event art. Gemini and Pred supply event-level art
only, so image inherits it there. Opinion supplies market-level art on standalone
markets and parent-event art on grouped markets. Kalshi art is series art: every
market in a series shares one picture, served in image and eventImage.
The series also exposes its art through the optional image field on fetchSeries.
Predictefy collects a series’ art when it refreshes that series, so a new series’
markets can return null for a while.
Treat every URL as an untrusted string: validate the scheme and host before rendering. Predictefy’s own console does not render venue images; the category placeholders are the only Predictefy-hosted pictures.
Eight-window price changes and tape coverage
Section titled “Eight-window price changes and tape coverage”For catalog markets served from the snapshot, Predictefy computes eight price-change windows on every outcome:
- Order-book tape (
tob_ticks):priceChange1m,priceChange5m, andpriceChange15mare computed from the top-of-book tick tape with zero freshness tolerance. - Candle history:
priceChange1h,priceChange6h, andpriceChange24hare computed from 1-minute stored candles (falling back to 1-hour candles if needed). - Official candles preferred:
priceChange7dandpriceChange30dprefer 1-hour and 1-day official venue candles before falling back to 1-minute aggregations.
Every window key is always present on snapshot-enriched market outcomes. A null value means
insufficient reference history at or before that window boundary — never zero. A zero value
is reserved for an honest, observed zero change.
Each outcome also includes a coverage object (or null when uncomputed) describing tape
provenance:
mechanism—ws-lossless,ws-top20,rest-adaptive,rest-top-of-book, orsynthetic-spottapeSince— ISO timestamp when continuous tape recording beganeffectiveIntervalMs— effective sampling interval in millisecondsgaps24h— number of detected tape gaps over the trailing 24 hourslastGapAt— ISO timestamp of the most recent gap, ornull
All eight windows are available as router-only stateless filterMarkets criteria keys
(priceChange1m through priceChange30d) accepting { outcome, min?, max? }.
filterEvents is the same helper at event grain, with the same contract: it is a pure stateless
filter, not a catalog query. You send { args: [events, criteria] } with an array you already
hold, and it returns the matching objects unchanged — it never fetches anything. Unknown criteria
fields, and the non-serializable function form, answer 400. Both are router-only; a non-router
exchange answers 400.
Prefer canonicalCategory and canonicalTags when screening across venues: category is
whatever the venue calls it, so filtering on it gives different results per venue. See
Categories & tags.
const shortlist = rows .filter((m) => (m.volume ?? 0) > 50_000) .sort((a, b) => (b.volume ?? 0) - (a.volume ?? 0)) .slice(0, 25);Note the ?? 0 on every nullable numeric. volume24h and liquidity are declared nullable, and
a null sorts unpredictably if you do not handle it.
The honesty fields
Section titled “The honesty fields”asOf, provenance and capabilities are required on every market record — the spec marks
them so. They are the difference between a screener that is right and one that looks right:
asOf— when the data was true. Show it.provenance— where it came from.capabilities—read,trade,depth,historyfor that record. Checkdepthbefore assuming you can size against a book, and read Capability-honest data for what each one does and does not promise.
Do not filter venues with a hard-coded list of which ones have real books. That list changes;
capabilities and Venue coverage do not go stale.
A catalog read is the cheapest call on the platform, but a sweep is many of them: 20 pages is 20
reads. Cap maxPages, and prefer a narrower query or a category filter over paginating the
whole catalog. Current weights are in Credits & billing.
fetchMarketsPaginated exists as an offset-paginated alternative when you genuinely need to
jump to a position rather than walk forward.
Related
Section titled “Related”- Categories & tags — canonical vs venue-native vocabulary
- Identifiers — which id each verb expects
- Compare one market across every venue — from a shortlist to a comparison