Skip to content
Elara One docs

Search

Results pages, instant search suggestions, the merchant's search settings, the anonymous search events beacon, synonyms and search rate limits.

Every store has a search index that ranks results, tolerates typos, and stays in step with the catalogue. Four endpoints cover it: a results page, suggestions as the shopper types, the merchant's search settings, and a beacon that records what shoppers click.

EndpointUse
GET /v1/searchThe results page: products, facets and filters
GET /v1/search/suggestInstant suggestions as the shopper types
GET /v1/search/configThe merchant's search settings for your search box
POST /v1/search/eventsAnonymous click and add-to-basket events from search

Search answers are never personalised. Call these endpoints from your storefront server without a bearer token or cart token.

The results page

GET /v1/search takes a query q and the same perPage, page and include parameters as the product list. An empty q lists every published product, which is useful for brand and tag pages.

ParameterMatches
qThe search text. Whitespace is trimmed and collapsed.
localeA store language code from GET /v1/search/config. Unknown or missing means the store's default. Always send it; the API does not read Accept-Language.
filter[collection]A collection slug
filter[brand]A brand slug. An unknown slug returns no products.
filter[tag]A tag value, exactly, ignoring case
filter[in_stock]1 for only products in stock
filter[on_sale]1 for only products on sale
filter[price_min], filter[price_max]Integer minor units of the store's currency, never decimals
filter[attr][handle]A filterable attribute's value
sortname, -name, price, -price or -created_at. Leave it out to sort by relevance.

Malformed parameters, such as a decimal price or filter[in_stock]=maybe, return 422 VALIDATION_FAILED.

curl -G https://api.elaraone.app/api/v1/search \
  -H "X-Tenant-Key: $ELARAONE_TENANT_KEY" \
  -H "X-Tenant-Secret: $ELARAONE_TENANT_SECRET" \
  -H "X-Client-IP: 203.0.113.7" \
  --data-urlencode "q=oak lamp" \
  --data-urlencode "locale=en" \
  --data-urlencode "filter[in_stock]=1" \
  --data-urlencode "include=variants.prices,images"

Besides the usual pagination fields, meta carries:

  • total: the number of matching products;
  • locale and currency: what the answer was searched and priced in;
  • facets: counts per value for each facet, such as collection_slugs, brand_slug, tags, in_stock, on_sale and attr_{handle} for each filterable attribute;
  • facet_labels: the heading to show for each facet, in display order;
  • facet_value_labels: display names for values that are identifiers, such as brand slugs;
  • search_engine: meilisearch normally, or database when the index is briefly unavailable. The answer is still a 200 with products, just without facets: render what you get.

Each successful answer also carries an X-Search-Id response header. Keep it to report clicks (below).

Instant suggestions

GET /v1/search/suggest returns grouped suggestions for a partly typed query.

GET /api/v1/search/suggest?q=oak%20de&locale=en&types=products,collections,pages
ParameterRules
qRequired, 1 to 200 characters after trimming. Shorter than the store's min_chars returns empty groups without searching.
localeAs for GET /v1/search
typesA comma-separated subset of products, collections, brands, tags, pages and posts. Missing means every type the merchant has switched on.
Response (trimmed)
{
  "data": {
    "query": "oak de",
    "products": {
      "total": 3,
      "hits": [
        {
          "id": 101,
          "slug": "oak-desk-lamp",
          "name": "Oak desk lamp",
          "name_html": "<mark>Oak</mark> <mark>de</mark>sk lamp",
          "image": { "url": "https://…/lamp-small.webp", "url_medium": "https://…/lamp-medium.webp", "alt": "Oak desk lamp" },
          "price": { "amount": 8900, "currency": "GBP", "formatted": "£89.00" },
          "price_max": null,
          "sale_price": null,
          "on_sale": false,
          "in_stock": true,
          "default_variant_id": 1543
        }
      ]
    },
    "collections": { "total": 0, "hits": [] }
  },
  "meta": { "search_engine": "meilisearch", "locale": "en", "currency": "GBP" }
}
  • A group is present only for types you asked for and the merchant has switched on. Treat a missing group as empty, and render groups in the order of autocomplete.types from the config.
  • name_html and title_html contain escaped text plus <mark> tags around the matched parts. Render them by splitting on <mark> and </mark> into text, never by injecting HTML.
  • default_variant_id is set when the product has exactly one variant you can buy, so an "Add to basket" button can add it directly.
  • Cancel the previous request when a new keystroke arrives, and keep the current suggestions on screen while the next ones load.

Search settings

GET /v1/search/config?locale=en returns the merchant's choices from Search settings in the admin: whether search and suggestions are on, min_chars, debounce_ms, which suggestion types to show and how many of each, popular searches, layout, colours, the placeholder and the no-results text. Use it instead of hard-coding these values.

The response carries an ETag and Cache-Control: max-age=60, private. Cache it for 60 seconds on your server and revalidate with If-None-Match; a 304 means nothing changed. meta.version changes whenever the merchant saves, so clear your suggestion cache when it does.

The search events beacon

POST /v1/search/events records what shoppers do with search results, so the merchant can see which searches lead to clicks and sales. Send events in batches of 1 to 20:

POST /v1/search/events
{
  "events": [
    { "type": "settled", "search_id": "01JB8Z6Q4M9W2C7XK3T5VYHNPR", "trigger": "idle" },
    { "type": "click", "search_id": "01JB8Z6Q4M9W2C7XK3T5VYHNPR", "item_type": "product", "item_id": "101", "position": 1 },
    { "type": "add_to_cart", "search_id": "01JB8Z6Q4M9W2C7XK3T5VYHNPR", "product_id": 101 }
  ]
}
EventSend whenFields
settledThe shopper stops typing in the suggestions box (idle), leaves it (blur) or presses Enter (enter)trigger
clickThe shopper chooses a resultitem_type (product, collection, brand, tag, page or post), item_id as a string, position from 1
add_to_cartThe shopper adds a product straight from searchproduct_id

The answer is always 202 Accepted with { "data": { "accepted": n } }. Events for an unknown or expired search id (ids last 15 minutes) are dropped quietly. Do not send settled for the results page: the engine records results-page searches itself.

No shopper identifiers. The beacon carries only the search id and what was chosen. Never send the query, customer ids or anything personal; the engine looks the query up from the search id and keeps only daily totals per query and per item. A 422 means a client bug: fix it rather than retrying. A 429 drops the batch; do not retry it.

Synonyms

Merchants teach search their own words under Search settings → Synonyms in the admin, with no code needed:

  • Multi-way synonyms make words equal: searching any of "sofa", "settee" and "couch" finds the others.
  • One-way synonyms widen one word only: "tableware" can also find "mug" and "tray" without "mug" finding everything that is tableware.

A store can have up to 1,000 rules, each with up to 20 terms, and can import and export them as CSV. Changes apply to suggestions and results alike.

Rate limits

EndpointBudget
GET /v1/search/suggest1,200 requests a minute per store and shopper IP
POST /v1/search/events300 batches a minute per store and shopper IP
GET /v1/search, GET /v1/search/configThe store's general API budget

Suggestions and events have their own budgets, so typing never uses up the general one. The budgets are per shopper only when your server sends X-Client-IP with the server secret; otherwise every shopper shares your server's IP. On a 429, keep the current results and wait for Retry-After. See rate limits.