SK

Search statistics API

Everything Ragnetiq Smart Search records about the search in your e-shop, as JSON over HTTPS.

Introduction

The API returns the search statistics of your e-shop: what the dashboard at search.ragnetiq.com shows, plus every single recorded event (search, click, add to cart) and every order the search captured. The data is yours: pull it into your own reporting, data warehouse or BI tool.

The base URL is https://search.ragnetiq.com/api/stats/v1. Every response is JSON in UTF-8; every timestamp is ISO 8601 in UTC. Requests are GET only; the API changes nothing.

  • One key covers all your shops (for example the Slovak and the Czech version).
  • You pick the period with from and to, at most 366 days at a time.
  • The aggregated reports (/summary, /queries, /products) are the same numbers as in the dashboard; the raw data (/events, /purchases) holds everything that was recorded.
  • No personal data of shoppers is stored: visitor and session identifiers are random, the order number is kept only as a hash.

Authentication

Ragnetiq issues your key. It is ss_ followed by 64 hexadecimal characters. Send it in the Authorization header with every request:

Authorization: Bearer ss_9f2c1a7e…

The key is as secret as a password. Use it from a server only (cron, backend, ETL), never in a browser or a mobile app. If it leaks, tell us: we revoke the old key and issue a new one; a revoked key stops working at once.

A missing, invalid or revoked key gets 401 unauthorized. A key without access to a requested shop gets 403 forbidden.

The rules shared by all Ragnetiq APIs (keys, paging, limits, errors, versions) are also on one page: API basics.

Common parameters and rules

Query parameters

ParameterValueMeaning
shopshop id, optionalLimits the data to one or more shops: ?shop=a, ?shop=a&shop=b or ?shop=a,b. Without it you get all the key's shops together. Ids come from /shops.
fromYYYY-MM-DD, optionalFirst day of the period (inclusive). Defaults to 29 days before to.
toYYYY-MM-DD, optionalLast day of the period (inclusive). Defaults to today. At most 366 days.
after, limitintegersPaging of the raw data, see below.

A day runs from midnight to midnight in Bratislava (Europe/Bratislava), as in the dashboard; every response states it in the timezone field. Adding up the shops one by one gives the same result as a request without shop, except revenue in different currencies, which is never summed.

Paging

/events and /purchases return at most 1,000 records at a time, oldest first. The response contains next: the id of the page's last record, or null when there is no further page. Ask for the next page with after=<next>. limit sets the page size (1 – 1,000, default 1,000).

Record ids are stable and grow over time, so after also works for incremental downloads: remember the last id and start from it next time.

Limits

  • At most 120 requests per minute per key; above that you get 429 rate_limited.
  • At most 366 days per request; download longer history in parts.
  • Data is available within seconds, so today's numbers keep changing. For closed numbers, download yesterday and earlier.

Errors

An error response always has the same shape: an HTTP status code, error with a machine-readable code and message with an explanation.

HTTP/1.1 403 Forbidden
Content-Type: application/json; charset=utf-8

{ "error": "forbidden", "message": "Kľúč nemá prístup k niektorému z požadovaných obchodov." }
HTTPerrorWhen
400invalid_periodfrom/to are not dates, to is before from, or the period exceeds 366 days.
400invalid_shop, invalid_paramA malformed shop, after, limit or type parameter.
401unauthorizedMissing, invalid or revoked key.
403forbiddenThe key does not cover one of the shops in shop.
429rate_limitedMore than 120 requests per minute. Wait and retry.
502, 503upstream, unavailableA temporary outage on our side. Retry later.

Error messages are in Slovak; rely on the error code.

Shops

GET/api/stats/v1/shops

The shops the key covers. Their id goes into the shop parameter and appears on every raw record.

curl "https://search.ragnetiq.com/api/stats/v1/shops" \
  -H "Authorization: Bearer ss_YOUR_KEY"
Response
{
  "shops": [
    { "id": "demo-shop", "name": "Demo Shop", "domains": ["www.demo-shop.example", "demo-shop.example"] }
  ]
}

Summary

GET/api/stats/v1/summary

The dashboard's first screen: totals for the period, the same for the equally long previous period (for comparison), values per day, the path from search to order, and the split by device.

curl "https://search.ragnetiq.com/api/stats/v1/summary?shop=demo-shop&from=2026-10-01&to=2026-10-15" \
  -H "Authorization: Bearer ss_YOUR_KEY"
Response (shortened)
{
  "shops": ["demo-shop"],
  "from": "2026-10-01",
  "to": "2026-10-15",
  "timezone": "Europe/Bratislava",
  "totals": {
    "searches": 10638,
    "searchers": 6489,
    "zero": 457,
    "not_confident": 638,
    "serp": 5851,
    "with_click": 4681,
    "clicks": 7215,
    "carts": 655,
    "latency_p50": 412,
    "orders": 465,
    "orders_search": 186,
    "revenue_search": 34782.4,
    "currency": "EUR",
    "revenue_by_currency": [{ "currency": "EUR", "value": 34782.4 }]
  },
  "previous": { "searches": 9574, "…": "…" },
  "daily": [
    { "day": "2026-10-01", "searches": 712, "clicks": 486, "carts": 41 },
    { "day": "2026-10-02", "searches": 698, "clicks": 471, "carts": 44 }
  ],
  "flow": {
    "zero":     { "total": 457,  "ordered": 4 },
    "no_click": { "total": 5500, "ordered": 15 },
    "click":    { "total": 4026, "ordered": 65 },
    "cart":     { "total": 655,  "ordered": 102 }
  },
  "devices": { "desktop": 4468, "mobile": 6170 },
  "recommendations": {
    "current": {
      "views": 18420, "clicks": 1104, "carts": 196, "orders": 61, "revenue": 11240, "currency": "EUR",
      "blocks": [
        { "block": "picks", "views": 9120, "clicks": 471, "carts": 72, "orders": 24, "revenue": 4310 },
        { "block": "similar", "views": 5410, "clicks": 402, "carts": 68, "orders": 21, "revenue": 3980 }
      ]
    },
    "previous": { "views": 16900, "clicks": 980, "carts": 171, "orders": 52, "revenue": 9870, "currency": "EUR", "blocks": [] }
  }
}

totals and previous

FieldTypeMeaning
searchesnumberNumber of searches. One search = one intent: the suggestions and the following Enter with the same words count once.
searchersnumberDistinct visitors who searched.
zeronumberSearches without a single result.
not_confidentnumberSearches without an exact match, where the closest products were shown instead.
serpnumberSearches that reached the results page (not only the suggestions).
with_clicknumberSearches after which the shopper opened at least one product.
clicksnumberAll product clicks from the results and the suggestions.
cartsnumberAdd-to-carts straight from the results list or the suggestions.
latency_p50number | nullMedian search response time in milliseconds (server side).
ordersnumberAll orders the search captured on the thank-you page (with or without a search).
orders_searchnumberOrders from visits in which the shopper searched during the 24 hours before ordering.
revenue_searchnumberValue of the orders_search orders, incl. VAT, in the shop's currency.
currencystring | nullCurrency of the revenue. null when the requested shops use different currencies; read revenue_by_currency then.
revenue_by_currencyarrayRevenue per currency: [{ currency, value }].

daily

One record per day of the period (zeros included): day (YYYY-MM-DD), searches, clicks, carts.

flow

Every search of the period falls into one branch by what the shopper did with the results list: zero (nothing found), no_click (results shown, no click), click (opened a product), cart (added to cart straight from the list). Each branch has total (searches) and ordered (orders of the same visit credited to these searches). The ordered values add up to orders_search.

devices

Searches by device: desktop, mobile, and possibly unknown (shops where the device is not recorded).

recommendations

The recommendation blocks in the shop (when the shop uses them; null otherwise). current covers the chosen period, previous the equally long period before it.

FieldTypeMeaning
viewsnumberHow many times a recommendation block was shown (once per page view and block).
clicksnumberProducts opened from a recommendation block.
cartsnumberAdd-to-carts straight from a recommendation block.
ordersnumberOrders from visits in which the shopper clicked a recommendation during the 24 hours before ordering.
revenue, currencynumber, string | nullValue of those orders incl. VAT and their currency.
blocksarrayThe same per block: block (picks homepage, similar on the product page, cart the cart, recent recently viewed), views, clicks, carts, orders, revenue (an order is credited to the block of the last click before it).

Queries

GET/api/stats/v1/queries

Three lists of up to 100 queries each. Queries are normalised (lower case, no diacritics, single spaces) so that “Vŕtačka” and “vrtacka” count together.

curl "https://search.ragnetiq.com/api/stats/v1/queries?from=2026-10-01&to=2026-10-15" \
  -H "Authorization: Bearer ss_YOUR_KEY"
Response (shortened)
{
  "shops": null,
  "from": "2026-10-01",
  "to": "2026-10-15",
  "timezone": "Europe/Bratislava",
  "top": [
    { "query": "vrtacka", "searches": 1912, "zero": 0, "with_click": 1190, "carts": 64 }
  ],
  "zero_results": [
    { "query": "vrtackaa", "searches": 64 }
  ],
  "no_click": [
    { "query": "nahradny diel 1234", "searches": 38 }
  ]
}
ListFieldsMeaning
topquery, searches, zero, with_click, cartsMost searched queries: searches, how many had no result, how many ended with a click, and add-to-carts from the list.
zero_resultsquery, searchesQueries that found nothing: candidates for synonyms or for the assortment.
no_clickquery, searchesQueries where products were shown but nobody clicked any. searches counts only searches with results.

Products

GET/api/stats/v1/products

Up to 100 products shoppers clicked or added to the cart from the search, ordered by clicks.

curl "https://search.ragnetiq.com/api/stats/v1/products?shop=demo-shop" \
  -H "Authorization: Bearer ss_YOUR_KEY"
Response (shortened)
{
  "shops": ["demo-shop"],
  "from": "2026-09-16",
  "to": "2026-10-15",
  "timezone": "Europe/Bratislava",
  "products": [
    { "id": "demo-shop:a1b2c3d4-…", "shop": "demo-shop", "product_id": "a1b2c3d4-…", "name": "Aku vŕtačka 18 V", "clicks": 412, "carts": 61 }
  ]
}

product_id is the product's identifier in your platform (for example a product GUID or code), so you can join it with your own catalogue. name is the name at the time of the last click.

Events (raw data)

GET/api/stats/v1/events

Every recorded search event, oldest first, in pages. This is the complete record: everything the aggregated reports compute can be derived from it.

ParameterValueMeaning
typesearch, click, cart, article, error, reco_view, reco_click, reco_cartOptionally one event type only.
afterintegerId of the last record of the previous page (next). Default 0.
limit1–1000Page size. Default 1,000.
curl "https://search.ragnetiq.com/api/stats/v1/events?from=2026-10-01&to=2026-10-15&type=search&limit=500" \
  -H "Authorization: Bearer ss_YOUR_KEY"
Response (shortened)
{
  "shops": null,
  "from": "2026-10-01",
  "to": "2026-10-15",
  "timezone": "Europe/Bratislava",
  "type": null,
  "items": [
    {
      "id": 48213,
      "shop": "demo-shop",
      "occurred_at": "2026-10-14T08:21:36.412Z",
      "type": "search",
      "surface": "autocomplete",
      "visitor_id": "6f1c2d5e-…",
      "session_id": "9a7b3e10-…",
      "search_id": "c2a4f8d1-…",
      "query": "aku vŕtačka",
      "query_norm": "aku vrtacka",
      "result_count": 42,
      "confident": true,
      "corrected": null,
      "filters": null,
      "product_id": null,
      "product_name": null,
      "position": null,
      "server_ms": 184,
      "client_ms": 412,
      "device": "desktop",
      "extra": null
    },
    {
      "id": 48214,
      "shop": "demo-shop",
      "occurred_at": "2026-10-14T08:21:41.907Z",
      "type": "click",
      "surface": "autocomplete",
      "visitor_id": "6f1c2d5e-…",
      "session_id": "9a7b3e10-…",
      "search_id": "c2a4f8d1-…",
      "query": "aku vŕtačka",
      "query_norm": "aku vrtacka",
      "result_count": null,
      "confident": null,
      "corrected": null,
      "filters": null,
      "product_id": "a1b2c3d4-…",
      "product_name": "Aku vŕtačka 18 V",
      "position": 1,
      "server_ms": null,
      "client_ms": null,
      "device": "desktop",
      "extra": null
    }
  ],
  "next": null
}

Event fields

FieldTypeMeaning
idnumberStable, growing record id; used for paging.
shopstringShop id.
occurred_attimestampWhen the event happened (UTC).
typestringsearch a search, click a product opened from a list, cart an add-to-cart from a list, article an article opened from the results, error a search error (some platforms only), reco_view a recommendation block was shown, reco_click a product opened from a recommendation, reco_cart an add-to-cart from a recommendation.
surfacestringautocomplete the suggestions, results the results page, reco a recommendation block.
visitor_iduuidRandom, long-lived browser identifier. Not a person.
session_iduuidRandom visit identifier (browser tab, or 30 minutes of inactivity).
search_iduuid | nullTies the events of one search together: the search, its clicks and carts share a search_id.
querystring | nullThe query as typed (up to 200 characters).
query_normstring | nullNormalised query (lower case, no diacritics).
result_countnumber | nullProducts found (for search).
confidentboolean | nullfalse = no exact match, the closest products were shown.
correctedstring | nullThe spelling correction the search applied.
filtersobject | nullFilters active during the search (brand, category, price, in stock…).
product_id, product_namestring | nullThe product, for click and cart.
positionnumber | nullPosition of the product in the list (from 1), for click and cart.
server_ms, client_msnumber | nullSearch duration on the server and in the browser, in milliseconds.
devicestring | nulldesktop, mobile, or null when not recorded.
extraobject | nullExtra fields specific to the shop's platform (for example market, search mode, quantity added to the cart, article URL, and for recommendations the block, the algorithm and the product it was made for). The structure may differ per shop.

Purchases (raw data)

GET/api/stats/v1/purchases

Orders the search captured on the thank-you page, oldest first, in pages (after and limit as for events). Each order appears once.

curl "https://search.ragnetiq.com/api/stats/v1/purchases?from=2026-10-01&to=2026-10-15" \
  -H "Authorization: Bearer ss_YOUR_KEY"
Response (shortened)
{
  "shops": null,
  "from": "2026-10-01",
  "to": "2026-10-15",
  "timezone": "Europe/Bratislava",
  "items": [
    {
      "id": 931,
      "shop": "demo-shop",
      "occurred_at": "2026-10-14T09:02:11.055Z",
      "order_hash": "7d2dd5fa939d8b5a…",
      "visitor_id": "6f1c2d5e-…",
      "session_id": "9a7b3e10-…",
      "value": 606.32,
      "currency": "EUR",
      "items": [{ "id": "a1b2c3d4-…", "quantity": 1, "price": 606.32 }],
      "extra": null,
      "after_search": true
    }
  ],
  "next": null
}
FieldTypeMeaning
idnumberStable, growing record id; used for paging.
shopstringShop id.
occurred_attimestampWhen the order was captured (UTC).
order_hashstringHash of the order number (SHA-256). The number itself is not stored; match with your system by items and time.
visitor_id, session_iduuidThe same identifiers as on events: they tie the order to a search.
valuenumber | nullOrder value incl. VAT.
currencystring | nullOrder currency.
itemsarrayOrder lines: [{ id, quantity, price }], where id is the product identifier as on events. Some platforms send only the product that came from the search.
after_searchbooleantrue when the shopper searched in the same visit during the 24 hours before the order. These orders make up orders_search in the summary.
extraobject | nullExtra fields specific to the platform.

Examples

Recommended routine: once a day (say in the morning) fetch /summary for yesterday for daily reports, and /events + /purchases incrementally from the last id you processed. Keep the key in an environment variable, not in code.

Node.js 18+ (fetch)
const BASE = "https://search.ragnetiq.com/api/stats/v1";
const headers = { Authorization: `Bearer ${process.env.SMARTSEARCH_API_KEY}` };

async function get(path, params = {}) {
  const url = new URL(BASE + path);
  for (const [k, v] of Object.entries(params)) if (v != null) url.searchParams.set(k, String(v));
  const res = await fetch(url, { headers });
  if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
  return res.json();
}

// September summary
const summary = await get("/summary", { from: "2026-09-01", to: "2026-09-30" });
console.log(summary.totals.searches, summary.totals.orders_search);

// all events, page by page
let after = 0;
do {
  const page = await get("/events", { from: "2026-09-01", to: "2026-09-30", after, limit: 1000 });
  for (const e of page.items) store(e); // your logic
  after = page.next;
} while (after);
Python (requests)
import os, requests

BASE = "https://search.ragnetiq.com/api/stats/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['SMARTSEARCH_API_KEY']}"}

def get(path, **params):
    r = requests.get(BASE + path, headers=HEADERS, params=params, timeout=30)
    r.raise_for_status()
    return r.json()

summary = get("/summary", **{"from": "2026-09-01", "to": "2026-09-30"})
print(summary["totals"]["searches"])

after = 0
while after is not None:
    page = get("/events", **{"from": "2026-09-01", "to": "2026-09-30", "after": after, "limit": 1000})
    for event in page["items"]:
        ...  # your logic
    after = page["next"]

Changes

DateVersionChange
18 Oct 2026v1Days are counted in the Europe/Bratislava time zone (previously UTC), as in the dashboard; responses carry a timezone field. Without from, the period starts 29 days before to.
16 Oct 2026v1/summary gains recommendations (the recommendation blocks); /events knows the types reco_view, reco_click, reco_cart.
16 Oct 2026v1First release: /shops, /summary, /queries, /products, /events, /purchases.

The version is in the URL (/v1). We may add new fields at any time; existing fields and their meaning do not change within a version. We will tell you in advance about any new version.