Search & Recommendation

These endpoints return results without an AI answer: a product grid, a "related articles" rail, a trending list, a type-ahead box.

Pick the right search for your catalog.

Your catalog Use Why
Articles, video, documents Hybrid Search A reader asks in words, and wants an answer as much as a list. Hybrid Search returns both from one call.
Products, listings, inventory The Search API on this page A shopper wants the matching items, fast, at high volume. No answer is generated, so nothing waits on a model.

The Search API is built for the e-commerce shape of the problem: heavy concurrent traffic, short queries, and a results page that has to render now. Hybrid Search is built for the content shape: fewer, longer questions, where an answer with citations is the point. For reference, Hybrid Search returns its results in about 2 seconds and finishes the answer about 5 seconds later.

Use both if you have both. They read the same catalog.

All of them take POST, a JSON body, and your secret key. See Authentication.

The examples on this page use the public Wikinews catalog, so you can load it and run them yourself. See Example: Wikinews.

These endpoints need an engine. Search and recommendation run on engines that Miso creates for your app in Dojo. Until one exists, every call here returns 404:

{ "message": "`search` engine is not found. Please create it in Dojo first or retry in a few seconds." }

The GenAI endpoints — answers, hybrid search, summaries — do not need one. If search returns this error while answers work, the engine is what is missing, not your key or your data.

Which one do I want?

You want Endpoint
Fast search over a product catalog POST /v1/search/search
A type-ahead box POST /v1/search/autocomplete
Several products by id, in one call POST /v1/search/mget
"More like this" on an article page POST /v1/recommendation/product_to_products
A personalized rail for one reader POST /v1/recommendation/user_to_products
What is popular now POST /v1/recommendation/user_to_trending
The categories a reader leans towards POST /v1/recommendation/user_to_categories
The attributes a reader leans towards POST /v1/recommendation/user_to_attributes
Several of the above in one round trip POST /v1/bulk

Every parameter and response is in the API Reference.

curl -X POST "https://api.askmiso.com/v1/search/search" \
  -H "X-Api-Key: YOUR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "q": "interest rates",
    "rows": 10,
    "fl": ["title", "url", "cover_image"],
    "fq": "custom_attributes.premium:\"false\"",
    "anonymous_id": "visitor-8f3a1c"
  }'
Field What it does
q The query.
rows, start Page size and offset.
fl Which product fields come back. Any field you uploaded, including a custom attribute.
fq A filter that restricts the candidates. It does not affect ranking.
user_id, anonymous_id Identify the reader, so Miso can personalize the order.

fq is the same filter syntax the answer APIs use, so a rule you write once works in both. See Filter Syntax (fq).

Recommendation

Every recommendation call needs a readeruser_id or anonymous_id. Without one you get 422 "Either user_id or anonymous_id need to be present". Most also take an anchor.

curl -X POST \
  "https://api.askmiso.com/v1/recommendation/product_to_products" \
  -H "X-Api-Key: YOUR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "product_id": "wikinews-2911067",
    "anonymous_id": "visitor-8f3a1c",
    "rows": 3,
    "fl": ["title", "url"]
  }'

The three product endpoints answer with the same shape:

{
  "message": "success",
  "data": {
    "took": 56,
    "miso_id": "0e4c3ccc-8c86-11f1-…",
    "products": [
      {
        "product_id": "wikinews-2911067",
        "title": "Red Hat to move focus away from CentOS in favour of Stream…",
        "url": "https://example.com/…",
        "_boosted": false
      }
    ]
  }
}
Field What it is
products The recommendations, in order. fl decides which fields each one carries.
_boosted true when a boost rule lifted this item.
_order_by The sort values, when you set your own order.
miso_id The request id. Send it back on an interaction to attribute the click.
took Milliseconds.

The two that do not return products

user_to_categories returns the categories a reader leans towards, and a few products for each. The category is an array, because it is a path through your hierarchy:

{
  "took": 1295,
  "miso_id": "1af2d2f6-8c86-11f1-…",
  "categories": [
    {
      "category": ["Computing"],
      "total": 0,
      "recommended_products": [
        {
          "product_id": "wikinews-2911293"
        }
      ]
    }
  ]
}

user_to_attributes does the same for one field, which you must name:

{
  "attributes": [
    {
      "value": "Computing",
      "total": 66,
      "recommended_products": [
        {
          "product_id": "wikinews-2911067"
        },
        {
          "product_id": "wikinews-2911293"
        }
      ]
    }
  ]
}

field is required here. Without it the call returns 422 "field required". A field that no record carries returns an empty attributes list, not an error.

Recommendations improve with interactions. user_to_products and user_to_trending read what your readers did. If you send no interactions, the results fall back to popularity. See Integrating Your Data.

Bulk API — one round trip for a whole page

A homepage often needs several units at once. POST /v1/bulk runs them together, so the page makes one request:

curl -X POST "https://api.askmiso.com/v1/bulk" \
  -H "X-Api-Key: YOUR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "requests": [
      { "api_name": "recommendation/user_to_trending",
        "body": { "anonymous_id": "visitor-8f3a1c", "rows": 6 } },
      { "api_name": "recommendation/product_to_products",
        "body": { "product_id": "wikinews-2911067",
                  "anonymous_id": "visitor-8f3a1c", "rows": 6 } }
    ]
  }'

Each entry needs api_name and body. Send 1 to 100 of them. Each body is the same JSON you post to that endpoint on its own, identity included.

api_name is {engine}/{endpoint}, with exactly one slash. A bare endpoint name is rejected before anything runs:

{
  "status_code": 400,
  "body": {
    "message": "API endpoint should be formatted in {engine_type}/{api_name}"
  }
}

Bulk carries engine APIs, so recommendation/… and search/… both work, and you can mix them in one call. The GenAI endpoints are not engines. Ask a question with the Answer API instead.

api_name Runs
recommendation/user_to_products Yes
recommendation/user_to_trending Yes
recommendation/product_to_products Yes
search/search, search/autocomplete Yes, once the search engine exists
ask/questions No. 400 Unknown engine type: ask

The response wraps each result, in the order you sent them:

{
  "errors": false,
  "data": [
    {
      "error": false,
      "status_code": 200,
      "body": {
        "message": "success",
        "data": {
          "took": 56,
          "miso_id": "…",
          "products": ["…"]
        }
      }
    }
  ]
}

One failing request does not stop the others, but it does change the outer status. A batch whose second request is malformed returns HTTP 422, with the first result intact:

{
  "errors": true,
  "data": [
    {
      "error": false,
      "status_code": 200,
      "body": {
        "…": "the products"
      }
    },
    {
      "error": true,
      "status_code": 422,
      "body": {
        "message": "Request schema error. See \"data.errors\" for details",
        "data": {
          "errors": [
            {
              "loc": ["__root__"],
              "msg": "Either user_id or anonymous_id need to be present"
            }
          ]
        }
      }
    }
  ]
}

So read errors and each status_code, not the HTTP status alone. An all-success run returns 200 with errors: false.

Bulk endpoints carry a tighter rate limit than the rest. See Errors & Rate Limits.

Report what the reader did

Results get better when Miso sees the outcome. Send an interaction when a reader views or clicks a unit:

curl -X POST "https://api.askmiso.com/v1/interactions" \
  -H "X-Api-Key: YOUR_PUBLISHABLE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "data": [
      {
        "type": "product_detail_page_view",
        "user_id": "u-10293",
        "product_ids": ["wikinews-2911067"],
        "timestamp": "2026-06-12T10:15:00Z"
      }
    ]
  }'

This is the one endpoint a publishable key can reach, so you can call it from the browser. The Miso SDK does it for you.