Skip to content
Get an API key

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.

Terminal window
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;
}

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.

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.
  • capabilitiesread, trade, depth, history for that record. Check depth before 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.