Features

Stage 2 of the Studio API pipeline. After Search generates candidates, the Features service enriches them with ML-computed personalization signals.

Search  →  Features  →  Scoring  →  Ranking
  ↓           ↓            ↓           ↓
Candidates  Enriched     Reranked    Final feed
from ES     with ML      by model    with diversity
            features                 & limits

Base URL: https://api.mbd.xyz/v3/studio Auth: Authorization: Bearer <your-console-api-key> — get your key from the Embed Console


Features

The Features service enriches items with ML-computed personalization signals by comparing each item against a user's profile.

Endpoint

POST /features/v1

Request

curl -X POST https://api.mbd.xyz/v3/studio/features/v1 \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "user": {
      "index": "polymarket-wallets",
      "id": "0xf68a281980f8c13828e84e147e3822381d6e5b1b"
    },
    "items": [
      { "index": "polymarket-items", "id": "1289113" },
      { "index": "polymarket-items", "id": "1288428" },
      { "index": "polymarket-items", "id": "1287500" }
    ]
  }'

Request Parameters

ParameterTypeRequiredDescription
userobjectYes{ index, id } — the user profile to compare against
itemsobject[]Yes[{ index, id }] — items to enrich with features

Response

{
  "result": {
    "user": {
      "_index": "polymarket-wallets",
      "_id": "0xf68a281980f8c13828e84e147e3822381d6e5b1b",
      "_source": {
        "user_id": "0xf68a281980f8c13828e84e147e3822381d6e5b1b",
        "primary_labels": ["mbd2:f_bullish", "mbd2:t_crypto"],
        "secondary_labels": ["mbd2:f_neutral"]
      }
    },
    "features": {
      "polymarket-items": {
        "1289113": {
          "found": 1,
          "original_rank": 1.0,
          "sem_sim_closest": 0.88,
          "sem_sim_fuzzy": 0.72,
          "usr_primary_labels": 0.67,
          "num_bets": 1,
          "bets": [
            {
              "user_pseudonym": "Baggy-Geology",
              "side": "BUY",
              "outcome": "Yes",
              "usdc": 500,
              "timestamp": "2026-02-15T10:30:00Z"
            }
          ]
        }
      }
    },
    "scores": {
      "polymarket-items": {
        "1289113": {
          "topic_score": 0.85
        }
      }
    },
    "feature_names": ["found", "original_rank", "sem_sim_closest", "sem_sim_fuzzy", "usr_primary_labels", "num_bets"],
    "score_names": ["topic_score"],
    "hit_rate": 0.95,
    "user_embed": true,
    "item_embed_rate": 1.0
  }
}

Important: Features are in result.features and scores are in result.scores — NOT result.items. The bets array inside each item's features contains recent trader activity on that market.

Feature Reference (in result.features)

FeatureWhat it measures
foundWhether the item was found in the index (0 or 1)
original_rankPosition in the original search results (0–1, higher = earlier)
sem_sim_closestBest cosine similarity between user and item embeddings (0–1)
sem_sim_fuzzyLoose semantic matching score (0–1)
sem_sim_1sem_sim_5Individual embedding similarity scores
usr_primary_labelsFraction of user's primary labels matching this item (0–1)
num_betsWhether similar items were bet on (0 or 1)
betsArray of recent trader activity (pseudonym, side, outcome, USDC, timestamp)
AI:{label}, TAG:{tag}Dynamic per-item match indicators for each user label/tag

Score Reference (in result.scores)

ScoreWhat it measures
topic_scorePre-computed composite relevance score (0–1, already normalized)

Error Handling

  • User not found: { "error": "user was not found in DynamoDB" } (HTTP 400)
  • Missing user param: { "error": "user is required" } (HTTP 400)

What's Next

  • Scoring & Ranking — Stage 3-4: rerank with trained models and apply diversity + limits
  • Search guide — Stage 1: filter_and_sort, boost, semantic, frequent_values
  • Filter Cookbook — All 12 filter types with per-index field tables and recipes

What’s Next

Learn about scoring and ranking