Screen markets across every venue
Sweep the catalog with cursor pagination, filter on normalized fields, and stop correctly.
One request returns at most 100 markets. Screening the catalog means paginating, and doing it with the cursor rather than with a page count.
Sweep
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
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[].priceChange1h / priceChange24h / priceChange7d | Optional absolute probability deltas |
asOf / provenance / capabilities | Required on every record — see below |
For open catalog markets served from the hot snapshot, Predictefy computes
outcomes[].priceChange1h, priceChange24h, and priceChange7d from its own candle history.
The fields are snapshot-only: SQL-fallback and settled responses may omit them. An absent field
means no reference history yet, never zero. The router-only stateless filterMarkets criteria
use the same three keys with { outcome, min?, max? }.
One-minute and five-minute change are deliberately not precomputed. At those windows, a cached
number is stale by definition. Compute them client-side from fetchOHLCV using the native 1m
and aggregated 5m resolutions (or a sub-minute resolution where the venue tape supports it),
or from the capability-qualified WebSocket price stream.
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
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.
Cost
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
- 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