Serving Feeds in Production
Once you've built and tested your algorithms in the Console, this guide shows you how to serve your feed config to users — with pagination, new item detection, and cache management.
How It Works
When you call the Serve endpoint, the platform:
- Runs each algorithm in your config
- Interleaves results according to the weights you set
- Caches the result
- Returns the first page of items plus a
served_idfor fetching more pages
Console Your App
┌──────────────┐
│ Algo A (0.6) │
│ Algo B (0.4) │──── config_id ───▶ POST /deploy/serve
│ Fallbacks │ │
│ Cache TTL │ ┌─────┴──────┐
└──────────────┘ │ served_id │
│ num_pages │
│ feed[] │
└─────┬──────┘
│
┌────────────┼────────────┐
▼ ▼ ▼
GET /page GET /new_items POST /cache/clear
(pagination) (pull to refresh) (after algo edit)
Step 1: Serve Your Feed
Call the Serve endpoint with your config_id and user context for personalization.
curl -X POST https://api.mbd.xyz/v3/studio/deploy/serve \
-H "Authorization: Bearer mbd-YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"config_id": 104,
"inputs": {
"farcasterFid": "16085",
"polymarketWallet": "0x1234..."
}
}'JavaScript:
const response = await fetch('https://api.mbd.xyz/v3/studio/deploy/serve', {
method: 'POST',
headers: {
'Authorization': 'Bearer mbd-YOUR_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
config_id: 104,
inputs: {
farcasterFid: '16085',
polymarketWallet: '0x1234...'
}
})
})
const { result } = await response.json()Python:
import requests
response = requests.post(
'https://api.mbd.xyz/v3/studio/deploy/serve',
headers={
'Authorization': 'Bearer mbd-YOUR_KEY',
'Content-Type': 'application/json'
},
json={
'config_id': 104,
'inputs': {
'farcasterFid': '16085',
'polymarketWallet': '0x1234...'
}
}
)
result = response.json()['result']- config_id — your saved feed config ID from the Console
- inputs — user context for personalization. Pass
{}for a non-personalized feed
Response
{
"result": {
"served_id": "707a68e8-2483-4b11-9180-5add8a8ec6e2",
"served_hash": "02a3ee745b36fea8",
"num_pages": 8,
"feed": [
{
"_id": "661295",
"_index": "polymarket-items-v20251126",
"_source": {
"question": "Will Bournemouth win the Carabao Cup?",
"outcome_prices": [0.5, 0.5],
"volume_1wk": 15000
}
}
],
"feeds_ages": {
"42": 0,
"43": 3600
},
"logs": [],
"took_algo_building": 120,
"took_backend": 180
}
}Save these values from the response:
| Field | What it's for |
|---|---|
served_id | Pass to the Page and New Items endpoints |
num_pages | Total pages available — controls your pagination UI |
feed | First page of items (default 25 per page) |
feeds_ages | Cache age in seconds per algorithm. 0 = fresh build |
Step 2: Paginate Through Results
Use the served_id from Step 1 to fetch additional pages. Pages are 1-based — page 1 was already returned in the feed array.
curl "https://api.mbd.xyz/v3/studio/deploy/serve/page?served_feed_id=707a68e8-2483-...&page_num=2" \
-H "Authorization: Bearer mbd-YOUR_KEY"JavaScript:
const params = new URLSearchParams({
served_feed_id: result.served_id,
page_num: String(2)
})
const pageResponse = await fetch(
`https://api.mbd.xyz/v3/studio/deploy/serve/page?${params}`,
{ headers: { 'Authorization': 'Bearer mbd-YOUR_KEY' } }
)
const { result: pageResult } = await pageResponse.json()Response
{
"result": {
"items": [
{ "_id": "661300", "_source": { "question": "Will Russia capture Shakhove?" } }
],
"new_items": 3
}
}- items — feed items for the requested page
- new_items — optional count of items published since your initial serve
Infinite Scroll Pattern
let currentPage = 1
const allItems = [...result.feed]
async function loadMore() {
if (currentPage >= result.num_pages) return
currentPage++
const params = new URLSearchParams({
served_feed_id: result.served_id,
page_num: String(currentPage)
})
const res = await fetch(
`https://api.mbd.xyz/v3/studio/deploy/serve/page?${params}`,
{ headers: { 'Authorization': 'Bearer mbd-YOUR_KEY' } }
)
const { result: pageResult } = await res.json()
allItems.push(...pageResult.items)
}Step 3: Check for New Items
After the initial serve, new content may be published. Use this endpoint to detect new items without re-fetching the entire feed — useful for "X new items available" banners or pull-to-refresh.
curl "https://api.mbd.xyz/v3/studio/deploy/serve/new_items?served_feed_id=707a68e8-2483-..." \
-H "Authorization: Bearer mbd-YOUR_KEY"Response
If new items exist:
{
"result": {
"items": [
{ "_id": "new_item_1", "_source": { "question": "Will BTC reach $150k by July?" } }
]
}
}If no new items exist, the API returns HTTP 404 with {"error": "New items not found"}. Handle this as "no new items" in your code:
const res = await fetch(...)
if (res.status === 404) {
// No new items — this is normal, not an error
return []
}
const { result } = await res.json()
return result.itemsPolling Pattern
function pollForNewItems(servedId, onNewItems, intervalMs = 60000) {
const poll = async () => {
const params = new URLSearchParams({ served_feed_id: servedId })
const res = await fetch(
`https://api.mbd.xyz/v3/studio/deploy/serve/new_items?${params}`,
{ headers: { 'Authorization': 'Bearer mbd-YOUR_KEY' } }
)
if (res.status === 404) return // no new items
const { result } = await res.json()
if (result.items && result.items.length > 0) {
onNewItems(result.items)
}
}
const interval = setInterval(poll, intervalMs)
return () => clearInterval(interval)
}Step 4: Preview Config Changes
Test different algorithm weights or settings without modifying your saved config:
const preview = await fetch('https://api.mbd.xyz/v3/studio/deploy/preview', {
method: 'POST',
headers: {
'Authorization': 'Bearer mbd-YOUR_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
config: {
main_algos: [
{ algo_id: 42, weight: 0.7 },
{ algo_id: 43, weight: 0.3 }
],
page_size: 25,
building_timeout_ms: 300
},
inputs: { farcasterFid: '16085' }
})
})Response is identical to /serve — you get a served_id and can paginate the preview.
Step 5: Clear Cache After Algorithm Updates
When you update an algorithm in the Console, cached feeds continue serving the previous version until the cache TTL expires. Force a refresh:
const clearResponse = await fetch('https://api.mbd.xyz/v3/studio/deploy/cache/clear', {
method: 'POST',
headers: {
'Authorization': 'Bearer mbd-YOUR_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
feedIds: [42, 43],
inputs: { farcasterFid: '16085' }
})
})- feedIds — these are algorithm IDs, not config IDs
- inputs — optional. If provided, only clears the cache for that specific user context
Response
{
"result": {
"42": { "denied": false, "found": 1 },
"43": { "denied": false, "found": 0 }
}
}found: 1— cache was clearedfound: 0— no cached version to clear
Handling Cold Starts
If your algorithms take longer than building_timeout_ms (default 150ms) to build, the API returns an empty feed:
{ "result": { "feed": [], "num_pages": 0, "served_id": "707a68e8-..." } }How to handle it:
- Increase the timeout — set
building_timeout_msto 300–500ms in your config - Retry with the served_id — the build continues in the background. Wait 1–2 seconds and fetch page 1:
const result = await serve(104, inputs)
if (result.feed.length === 0 && result.served_id) {
await new Promise(resolve => setTimeout(resolve, 2000))
const params = new URLSearchParams({
served_feed_id: result.served_id,
page_num: '1'
})
const retryResponse = await fetch(
`https://api.mbd.xyz/v3/studio/deploy/serve/page?${params}`,
{ headers: { 'Authorization': 'Bearer mbd-YOUR_KEY' } }
)
const { result: retryResult } = await retryResponse.json()
}- Show a loading state — display a skeleton UI rather than "no results found"
Debugging Multi-Algorithm Configs
When your config has two or more algorithms, the serve response doesn't indicate which algorithm produced which item. To debug:
- Check
feeds_ages— shows cache age per algorithm ID.0= fresh, any other value = cached. - Preview each algo separately — use
/deploy/previewwith one algorithm at a time:
// Test algo 42 alone
const algoA = await preview({
main_algos: [{ algo_id: 42, weight: 1.0 }]
}, inputs)
// Test algo 43 alone
const algoB = await preview({
main_algos: [{ algo_id: 43, weight: 1.0 }]
}, inputs)- Check the logs — the
logsarray in the response may contain debugging output from your algorithm code.
Complete Example
const API_BASE = 'https://api.mbd.xyz/v3/studio/deploy'
const API_KEY = 'mbd-YOUR_KEY'
const headers = {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
}
// 1. Serve the feed
const serveResponse = await fetch(`${API_BASE}/serve`, {
method: 'POST',
headers,
body: JSON.stringify({
config_id: 104,
inputs: { farcasterFid: '16085' }
})
})
const { result } = await serveResponse.json()
console.log(`Page 1: ${result.feed.length} items, ${result.num_pages} total pages`)
// 2. Fetch remaining pages
for (let page = 2; page <= result.num_pages; page++) {
const params = new URLSearchParams({
served_feed_id: result.served_id,
page_num: String(page)
})
const pageResponse = await fetch(`${API_BASE}/serve/page?${params}`, { headers })
const { result: pageResult } = await pageResponse.json()
console.log(`Page ${page}: ${pageResult.items.length} items`)
}
// 3. Poll for new items every 60 seconds
setInterval(async () => {
const params = new URLSearchParams({ served_feed_id: result.served_id })
const res = await fetch(`${API_BASE}/serve/new_items?${params}`, { headers })
const { result: newItems } = await res.json()
if (newItems.items?.length) {
console.log(`${newItems.items.length} new items since last serve`)
}
}, 60000)Python:
import requests
import time
API_BASE = 'https://api.mbd.xyz/v3/studio/deploy'
headers = {
'Authorization': 'Bearer mbd-YOUR_KEY',
'Content-Type': 'application/json'
}
# 1. Serve the feed
serve_response = requests.post(f'{API_BASE}/serve', headers=headers, json={
'config_id': 104,
'inputs': {'farcasterFid': '16085'}
})
result = serve_response.json()['result']
print(f"Page 1: {len(result['feed'])} items, {result['num_pages']} total pages")
# 2. Fetch remaining pages
for page in range(2, result['num_pages'] + 1):
page_response = requests.get(f'{API_BASE}/serve/page', headers=headers, params={
'served_feed_id': result['served_id'],
'page_num': page
})
items = page_response.json()['result']['items']
print(f"Page {page}: {len(items)} items")
# 3. Check for new items
new_items_response = requests.get(f'{API_BASE}/serve/new_items', headers=headers, params={
'served_feed_id': result['served_id']
})
new_items = new_items_response.json()['result']['items']
print(f"{len(new_items)} new items since last serve")What's Next
- Feed Deployment Status → — Understand warmup tiers (Draft, Group, Live)
- Feed Configs → — Create and manage feed configurations
- API Reference: Feed Serving — Full endpoint specifications
- [Quickstart: Algorithms DSL](../Getting Started/quickstart-studio-sdk) — Build custom pipelines
Updated 10 days ago
