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 finds markets that
mean the same thing without sharing words, and hybrid does both — useful when you are
screening a topic rather than a phrase.
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 |
asOf / provenance / capabilities |
Required on every record — see below |
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