Documentation

Search API — Reference

Everything you need to index a catalog and run a first search in minutes. Base URL: https://api.heurix.fr

Access requires an API key. Sign up self-service to get one immediately, or contact us for custom needs.

Introduction

The Search API exposes the Heurix engine: a search engine built for technical catalogs, where queries and product records go through the same pipeline — normalization (case, accents), business synonyms, typo tolerance, then a rule cascade that turns text into structured annotations. That cascade is what lets m8x20 find a record stored as "M8 x 20 — A2".

The API is REST, JSON, HTTPS only. All responses are UTF-8 encoded.

Quickstart

Three calls are enough for a working first search.

1 Index your products (the catalog is created automatically on first send):

curl -X POST https://api.heurix.fr/v1/index/mycatalog/items \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "rulepack": "outillage",
    "items": [
      {"id": "V1", "name": "Hex head screw", "ref": "M8 x 20 — A2", "stock": 100},
      {"id": "V2", "name": "Hex head screw", "ref": "M8 x 30 — A2", "stock": 50}
    ]
  }'

2 Search — typos are welcome:

curl -X POST https://api.heurix.fr/v1/index/mycatalog/search \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"q": "m8x20 stainless"}'

3 Read the response — every result explains why it matched:

{
  "query": "m8x20 stainless",
  "total": 2,
  "hits": [
    {
      "product": {"id": "V1", "name": "Hex head screw", "ref": "M8 x 20 — A2", "stock": 100},
      "score": 37.5,
      "in_stock": true,
      "matched": ["annotation #VIS_M8X20", "annotation #DIAM_M8", "annotation #LONG_20"]
    }
  ]
}

Authentication

Every call must carry your API key in the Authorization header:

Authorization: Bearer hx_your_api_key

A missing or malformed key returns 401; an invalid key returns 403. Keep your key server-side — never expose it in your site's public JavaScript. If your key leaks, contact us for immediate rotation.

Request counting

Billing is based on a monthly request counter, simple by design:

Search1 search call = 1 request
Indexingnever counted against your request quota — update your catalog as often as needed, only the total number of indexed products is capped by plan
Federated search1 request per catalog queried
ManagementEvery other API call (synonyms, stats, deletion...) = 1 request
Overage (Scale)Extra usage is billed at the rate shown on the pricing page — never a cutoff
Overage (other plans)A 10% grace margin absorbs a one-off spike; beyond that, the request is rejected with a clear 429 code

Your current usage is available anytime via GET /v1/usage.

Plans and limits

Every API key is tied to a plan that defines its monthly request volume, its indexable product count, and its number of catalogs. Feature details for each plan are on the pricing page; here are the raw limits:

PlanRequests / monthMax productsCatalogs
Trial (14 days)2,0002,0002
Starter — €19/month15,0008,0001
Growth — €49/month30,00025,0003
Scale — €139/month150,000 then billed100,000unlimited

Past the 14-day trial without subscribing to a paid plan, a key automatically reverts to trial limits until subscription — your catalogs and their configuration remain intact, simply less accessible in volume until you move to a paid plan.

Exceeding a limit returns a 429 code with the detail of the cause:

{
  "detail": "Starter plan request limit exceeded (5,512/5,000, 10% grace margin also exceeded). Upgrade to a higher plan to continue.",
  "plan": "starter",
  "limit_type": "requests",
  "upgrade_url": "https://heurix.fr/pricing.html"
}

Product structure

A product is a free-form JSON object. Four fields play a special role:

FieldTypeRole
idstring requiredUnique identifier within the catalog. Re-indexing the same id replaces the product (upsert).
refstringProduct reference (SKU, manufacturer code). Indexed, highest weight.
namestringProduct name. Indexed, high weight.
descriptionstringDescription. Indexed, standard weight.
stocknumber | bool | stringAvailability — used for sorting at equal relevance. 0, false, "out" = unavailable.

Any other field (price, image, URL, category...) is stored as-is and returned in results, without being indexed.

Facets and filters

A facet groups the annotations that share a common prefix — PAYS_SE and PAYS_FR belong to the PAYS group. Request a per-group count with facets, narrow results with filters:

curl -X POST https://api.heurix.fr/v1/index/mycatalog/search \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{"q": "crime", "facets": ["PAYS", "FORMAT"], "filters": ["PAYS_SE"]}'
{
  "total": 12,
  "hits": [ ... ],
  "facets": {
    "PAYS":   {"PAYS_SE": 12, "PAYS_FR": 34, "PAYS_UK": 9},
    "FORMAT": {"FORMAT_PO": 8, "FORMAT_BR": 4}
  }
}

Counting is disjunctive within a single group: filtering on PAYS_SE doesn't make PAYS_FR disappear from the count — that's what lets you show "France (34)" as an alternative option even once Sweden is selected, exactly like a standard e-commerce filter sidebar. Across different groups, however, filters remain cumulative (logical AND).

POST/v1/federated-search

Federated search

Queries multiple catalogs in a single call and merges results by relevance — useful for a multilingual site (one catalog per language) or multi-brand setup. Scoring weights are global to the engine, not per-catalog: scores stay comparable across catalogs, even with different rule packs.

Request body

ParameterTypeDescription
catalogsarray of string required1 to 10 catalog names to query.
qstringThe search query.
limit / offsetintegerPagination over the merged set.

Response

Same shape as a regular search, with a catalog field added to each hit to identify its source, and catalogs_searched / catalogs_not_found to spot an invalid catalog name.

curl -X POST https://api.heurix.fr/v1/federated-search \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{"catalogs": ["store-fr", "store-en"], "q": "red sweater"}'

Counting: 1 request per catalog actually queried — federating across 3 catalogs counts as 3 requests, same principle as batch indexing.

POST/v1/index/{catalog}/items

Indexing

Adds or updates products in batch (upsert on id). The catalog is created automatically if it doesn't exist. Optional featured field (boolean): marks a product as a candidate for the fallback shown when a search finds nothing — see Search, zero-result fallback.

Request body

ParameterTypeDescription
itemsarray required1 to 5,000 products per call. Every product must have an id.
rulepackstringRule pack to attach to the catalog (outillage, mode, industrie). Changing the pack re-indexes the catalog.

Response

{"indexed": 2, "catalog": {"catalog": "mycatalog", "products": 2, "terms": 11,
 "annotations": 9, "rulepack": "outillage", "synonym_groups": 0}}
DELETE/v1/index/{catalog}/items/{id}

Deletion

Removes a product from the index and storage. Returns 404 if the id is unknown.

curl -X DELETE https://api.heurix.fr/v1/index/mycatalog/items/V1 \
  -H "Authorization: Bearer YOUR_API_KEY"
GETPUT/v1/index/{catalog}/synonyms

Synonyms

Business synonyms expand search: "screw" can find "bolt". GET reads the current groups, PUT replaces them entirely. Groups sharing a term are merged automatically.

curl -X PUT https://api.heurix.fr/v1/index/mycatalog/synonyms \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"groups": [["screw", "bolt"], ["nut", "ecrou"]]}'
GET/v1/index/{catalog}/stats

Statistics

Catalog state: number of products, indexed terms, annotations produced by the cascade, active rule pack, synonym groups.

GET/v1/usage

Usage

Request counter for the current month, for the calling key.

{"month": "2026-07", "requests": 1284}
GET/v1/rulepacks

Rule packs

Lists the packs available on your instance, with their level and rule counts. Three standard packs ship by default: outillage (fasteners, DIN/ISO standards, materials), mode (sizes, colors, materials, families), industrie (bearings, standardized references). Custom packs for your catalog can be designed as a ROI Simulator mission.

GET/health

Service health

Liveness, no authentication — handy for your monitoring probes.

{"status": "ok", "catalogs": 3}

The annotation cascade

This is the engine's core. A rule pack is organized in levels: level 1 applies regular expressions to normalized text and produces annotations; the next levels apply to the annotation stream and compose them. Documents and queries go through the same cascade, so matching happens in a shared space:

"m8x20 stainless"                       "M8 x 20 — A2"   (product record)
      │                                        │
      ▼  level 1                               ▼  level 1
DIAM_M8, LONG_20, MAT_INOX             DIAM_M8, LONG_20, MAT_INOX
      │                                        │
      ▼  level 2                               ▼  level 2
VIS_M8X20  ──────────── match ─────────────  VIS_M8X20

Every shared annotation weighs heavily in the score — that's what puts the right reference first even when the written form differs. The matched field of each result makes those annotations visible.

Good practices

Fill ref, name, and description separately. Field weighting is what makes ranking good — concatenating everything into name flattens relevance.

Keep references as they are. Don't "clean" product references before indexing (stripping spaces, dashes...): normalization and the cascade handle it, and the original form stays available for display.

Index in batches of 1,000 to 5,000. One batch = one network call; too small multiplies calls, the cap is 5,000 per call.

Send stock with every update. Tie-break sorting relies on it; up-to-date stock avoids promoting unavailable products.

One catalog per language. If your store exists in French and English, create store-fr and store-en — synonyms and rules stay consistent per language.

Use matched to tune relevance. Every result explains why it ranks: if a product surfaces wrongly, this field shows which term or annotation made it match — it's your diagnostic tool.

Error codes

CodeMeaningWhat to do
401Authorization header missing or malformedSend Authorization: Bearer <key>
403Invalid API keyCheck the key; contact us if it was revoked
404Catalog or product not foundCheck the catalog name and id — the catalog is created on first indexing call, not before
422Invalid request bodyThe error detail names the field at fault (e.g. product missing an id)
5xxServer-side errorRetry; if it persists, write to contact@heurix.fr

Limits

Search query500 characters maximum
Results per page100 maximum (limit)
Indexing5,000 products per call — send multiple batches for a larger catalog
Synonym groups2,000 per catalog
CORSBrowser calls are not open: call the API from your server, not from public JavaScript (your key would be exposed)

Need more than these limits? Let's talk — that's what the Scale plan and dedicated setups are for.

14-day free trial

Try the Search API on your catalog, no credit card.

See pricing