Search
The Search service is Stage 1 of the Studio API pipeline. It generates candidate items from Elasticsearch using structured filters, relevance boosting, or semantic similarity.
Base URL: https://api.mbd.xyz/v3/studio
Auth: Authorization: Bearer <your-console-api-key> — get your key from the Embed Console
Search Endpoints
| Method | Endpoint | Purpose |
|---|---|---|
| POST | /search/filter_and_sort | Structured queries with filters + field-based sorting |
| POST | /search/boost | Soft relevance tuning with boost multipliers |
| POST | /search/semantic | Text or vector similarity search |
| GET | /search/frequent_values/{index}/{field} | Discover field values before filtering |
Searchable Indices
| Index | Content | Primary Use Case |
|---|---|---|
polymarket-items | Prediction markets | Market discovery, trading feeds |
polymarket-wallets | Trader profiles | Wallet lookup, leaderboards |
farcaster-items | Social posts | Social feeds, content discovery |
zora-coins | NFT coins/tokens | Creator economy, minting feeds |
filter_and_sort
The primary search endpoint. Returns items matching your filters, sorted by any numeric or date field.
Request
curl -X POST https://api.mbd.xyz/v3/studio/search/filter_and_sort \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"index": "polymarket-items",
"size": 20,
"sort_by": { "field": "volume_24hr", "order": "desc" },
"include": [
{ "filter": "term", "field": "active", "value": true },
{ "filter": "numeric", "field": "liquidity_num", "operator": ">", "value": 10000 }
],
"exclude": [
{ "filter": "term", "field": "closed", "value": true },
{ "filter": "term", "field": "archived", "value": true },
{ "filter": "term", "field": "price_0_or_1", "value": true }
],
"select_fields": ["question", "liquidity_num", "volume_24hr", "best_ask", "end_date", "ai_labels_med", "slug", "tags"]
}'Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
index | string | Yes | One of: polymarket-items, polymarket-wallets, farcaster-items, zora-coins |
size | number | No | Number of results (default 100, max 10000) |
sort_by | object | No | { field, order } — sort by any numeric or date field |
include | Filter[] | No | AND logic — all must match |
exclude | Filter[] | No | NOT logic — any match removes |
only_ids | boolean | No | Return only item IDs (faster) |
select_fields | string[] | No | Return only these fields from _source. Recommended — Polymarket documents have 50+ fields; only fetch what you need |
include_vector | boolean | No | Include embedding vectors in results |
Response
{
"query": { "...": "the ES query executed (useful for debugging)" },
"result": {
"took_es": 45,
"took_es_roundtrip": 52,
"total_hits": 834,
"max_score": null,
"hits": [
{
"_index": "polymarket-items-v20251024",
"_id": "1289113",
"_score": null,
"_source": {
"item_id": "1289113",
"question": "Will Bitcoin reach $150K by June 2026?",
"active": true,
"liquidity": 245000.50,
"volume_24hr": 1520340.00,
"best_ask": 0.62
}
}
]
},
"error": null
}Key fields to extract for later pipeline stages:
_id— the item ID to pass to Features and Scoring_source— metadata for display and ranking
boost
Same filter interface as filter_and_sort, but adds a boost array for soft relevance tuning. Items matching boost filters get score multipliers without being hard-filtered.
Does not support sort_by — results are ordered by relevance score.
Request
curl -X POST https://api.mbd.xyz/v3/studio/search/boost \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"index": "polymarket-items",
"size": 30,
"include": [
{ "filter": "term", "field": "active", "value": true }
],
"boost": [
{ "filter": "numeric", "field": "liquidity_num", "operator": ">", "value": 50000, "boost": 3.0 },
{ "filter": "term", "field": "featured", "value": true, "boost": 1.5 }
],
"exclude": []
}'The boost array accepts the same filter types as include/exclude, plus a boost multiplier (number). Higher values = stronger preference.
Wallet Personalization with group_boost
The group_boost filter dynamically looks up a wallet's preferences and boosts matching items. It reads {group}_01, {group}_02, …, {group}_N from the wallet document and applies linearly decreasing boosts (first match = max_boost, last = min_boost).
curl -X POST https://api.mbd.xyz/v3/studio/search/boost \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"index": "polymarket-items",
"size": 50,
"include": [
{ "filter": "term", "field": "active", "value": true },
{ "filter": "numeric", "field": "liquidity_num", "operator": ">", "value": 5000 }
],
"exclude": [
{ "filter": "term", "field": "closed", "value": true },
{ "filter": "term", "field": "price_0_or_1", "value": true }
],
"boost": [
{
"filter": "group_boost",
"field": "ai_labels_med",
"value": "0xf68a281980f8c13828e84e147e3822381d6e5b1b",
"lookup_index": "polymarket-wallets",
"group": "label",
"min_boost": 1,
"max_boost": 5,
"n": 5
},
{
"filter": "group_boost",
"field": "tags",
"value": "0xf68a281980f8c13828e84e147e3822381d6e5b1b",
"lookup_index": "polymarket-wallets",
"group": "tag",
"min_boost": 1,
"max_boost": 3,
"n": 5
}
],
"select_fields": ["question", "liquidity_num", "volume_24hr", "best_ask", "end_date", "ai_labels_med", "slug", "tags"]
}'Use group: "label" to match the wallet's label_01…label_N fields against item ai_labels_med, and group: "tag" to match tag_01…tag_N against item tags. The user's top interests get the strongest boost.
semantic
Text or vector similarity search using embeddings. Returns items ranked by semantic closeness to your query.
Does not support include/exclude filters or sort_by.
Request (text query)
curl -X POST https://api.mbd.xyz/v3/studio/search/semantic \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"index": "polymarket-items",
"text": "artificial intelligence regulation and policy",
"size": 20,
"select_fields": ["item_id", "question", "liquidity_num", "volume_24hr"]
}'Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
index | string | Yes | Target index |
text | string | One of text/vector | Natural language query (min 5 chars) |
vector | number[] | One of text/vector | 768-dimension embedding vector |
size | number | No | Number of results |
select_fields | string[] | No | Fields to return |
Tip: To combine semantic search with filtering, run semantic search first, collect the item IDs, then run
filter_and_sortwith{ "filter": "terms", "field": "item_id", "value": [...ids] }in the include array.
frequent_values
Discover what values exist in a field before building filters. Useful for exploring AI labels, categories, and other keyword fields.
Request
curl -X GET "https://api.mbd.xyz/v3/studio/search/frequent_values/polymarket-items/ai_labels_med?size=50" \
-H "Authorization: Bearer YOUR_API_KEY"Response
[
{ "id": "mbd2:f_neutral", "count": 8765 },
{ "id": "mbd2:f_positive", "count": 5432 },
{ "id": "mbd2:t_science_technology", "count": 3876 }
]Filter Logic
Every filter_and_sort and boost request accepts three filter arrays:
| Array | Logic | Effect |
|---|---|---|
include | AND — all must match | A document must satisfy every include filter |
exclude | NOT — any match removes | A document matching any exclude filter is removed |
boost | SHOULD — soft relevance | Matching documents get a score multiplier (boost endpoint only) |
Combined logic: (include[0] AND include[1] AND ...) AND NOT (exclude[0] OR exclude[1] OR ...)
Quick Reference: All 12 Filter Types
| Type | Description | Key Properties |
|---|---|---|
term | Exact match on a single value | field, value (string/boolean) |
terms | Match any of multiple values (OR) | field, value (string array) |
numeric | Range comparison (>, >=, <, <=) | field, operator, value (number) |
match | Full-text keyword search | field, value (string array) |
date | Date range filtering | field, value ({ date_from?, date_to? }) |
geo | Geographic distance | field, value (["geo:lat,lon"]) |
is_null | Field is null/missing | field |
not_null | Field exists and has a value | field |
custom | Raw Elasticsearch query clause | field, value (ES query object) |
group_boost | Dynamic wallet personalization — looks up {group}_01…{group}_N fields from a wallet document and applies linearly decreasing boosts (boost only) | lookup_index, field, value, group, min_boost, max_boost, n |
terms_lookup | Match against terms from another document | lookup_index, field, value, path |
console_account | Match against console account data | field, value, path |
For detailed examples, per-index filterable fields, AI label taxonomy, and ready-to-use recipes, see the Filter Cookbook.
Examples
Polymarket: Active High-Volume Markets
{
"index": "polymarket-items",
"size": 25,
"sort_by": { "field": "volume_24hr", "order": "desc" },
"include": [
{ "filter": "term", "field": "active", "value": true },
{ "filter": "numeric", "field": "liquidity_num", "operator": ">", "value": 10000 },
{ "filter": "numeric", "field": "volume_24hr", "operator": ">", "value": 100 }
],
"exclude": [
{ "filter": "term", "field": "closed", "value": true },
{ "filter": "term", "field": "archived", "value": true },
{ "filter": "term", "field": "price_0_or_1", "value": true }
],
"select_fields": ["question", "liquidity_num", "volume_24hr", "spread", "best_ask", "last_trade_price", "end_date", "ai_labels_med", "slug", "tags"]
}Field name gotchas (Polymarket):
- Use
liquidity_numnotliquidityfor filtering —liquiditycan be null and will silently miss results.- Use
ai_labels_mednotai_labels— the fieldai_labelsdoes not exist.- Use
slugnotmarket_slug—market_slugdoes not exist.- Exclude
closed,archived, andprice_0_or_1markets to filter out resolved/inactive content.
Polymarket: Wallets by PnL
{
"index": "polymarket-wallets",
"size": 25,
"sort_by": { "field": "pnl", "order": "desc" },
"include": [
{ "filter": "numeric", "field": "volume", "operator": ">", "value": 100000 }
],
"exclude": []
}Farcaster: English Posts by Popularity
{
"index": "farcaster-items",
"size": 20,
"sort_by": { "field": "score_popular", "order": "desc" },
"include": [
{ "filter": "term", "field": "lang", "value": "en" },
{ "filter": "numeric", "field": "num_like", "operator": ">=", "value": 10 }
],
"exclude": [
{ "filter": "numeric", "field": "user_score_spam", "operator": ">", "value": 0.5 }
]
}Zora: New Coins with Market Activity
{
"index": "zora-coins",
"size": 30,
"sort_by": { "field": "zora_created_at", "order": "desc" },
"include": [
{
"filter": "date",
"field": "zora_created_at",
"value": { "date_from": "2026-02-05T00:00:00Z" }
},
{ "filter": "numeric", "field": "zora_unique_holders", "operator": ">=", "value": 10 }
],
"exclude": [
{ "filter": "numeric", "field": "score_spam", "operator": ">", "value": 0.5 }
]
}What's Next
- Filter Cookbook — All 12 filter types with per-index field tables, AI label taxonomy, and 12 ready-to-use recipes
- Features — Stage 2: enrich items with ML features
- Scoring & Ranking — Stage 3-4: rerank with trained models and apply diversity
- Quickstart — Full 4-stage pipeline walkthrough with copy-paste code
Looking for the legacy Feed Builder filters? They're documented in Feed Builder 201.
Updated 7 days ago
Dive deeper with the Filter Cookbook
