# Management API

The control plane's API for catalogs, imports, releases, rules, synonyms and index runs, called with the management key.

Base URL in the compose stack: `http://127.0.0.1:8000`. Every call sends the management key as `Authorization: Bearer <key>` ([Authentication](/docs/reference/conventions#authentication)). [Conventions](/docs/reference/conventions) covers what both APIs share.

| Endpoint | What it does |
| --- | --- |
| [`PUT /api/v1/catalog`](#upload-catalog) | Replace the catalog |
| [`GET /api/v1/catalog-source`](#show-catalog-source) | Show the feed the catalog is fetched from, with its latest fetches |
| [`PUT /api/v1/catalog-source`](#set-catalog-source) | Fetch the catalog from a feed URL on a schedule |
| [`DELETE /api/v1/catalog-source`](#remove-catalog-source) | Stop fetching the catalog from its feed URL |
| [`POST /api/v1/catalog-source/fetch`](#fetch-catalog-source) | Fetch the catalog source now |
| [`GET /api/v1/imports`](#list-imports) | List the imports, newest first |
| [`POST /api/v1/imports`](#create-import) | Start an import: keep an export without making it live |
| [`GET /api/v1/imports/{import}`](#show-import) | Show an import with its files and its run |
| [`PATCH /api/v1/imports/{import}`](#change-import) | Change the release files an import is read with |
| [`DELETE /api/v1/imports/{import}`](#discard-import) | Discard an import that has not gone live |
| [`GET /api/v1/imports/{import}/inspection`](#inspect-import) | Show what the import makes of its export |
| [`GET /api/v1/imports/{import}/suggestions`](#suggest-mapping) | Show where a decision model would send the export's columns |
| [`GET /api/v1/imports/{import}/changes`](#show-import-changes) | Show what making an import live changes |
| [`POST /api/v1/imports/{import}/publish`](#publish-import) | Make an import live, or go back to an earlier one |
| [`GET /api/v1/imports/{import}/publication`](#show-import-publication) | Show how publishing the import would go live, before it does |
| [`GET /api/v1/rules`](#list-rules) | List the live rules in order, each with its state and its conflicts |
| [`GET /api/v1/imports/{import}/rules`](#list-draft-rules) | List a draft's rules in order, each with its state and its conflicts |
| [`POST /api/v1/imports/{import}/rules`](#create-rule) | Add a rule to a draft |
| [`PATCH /api/v1/imports/{import}/rules/{rule}`](#change-rule) | Change one rule of a draft |
| [`DELETE /api/v1/imports/{import}/rules/{rule}`](#delete-rule) | Remove one rule from a draft |
| [`PUT /api/v1/imports/{import}/rules/{rule}/position`](#move-rule) | Move one rule of a draft to another place in the order |
| [`GET /api/v1/synonyms`](#list-synonyms) | List the live synonyms of every language |
| [`GET /api/v1/imports/{import}/synonyms`](#list-draft-synonyms) | List a draft's synonyms of every language |
| [`POST /api/v1/imports/{import}/synonyms`](#add-synonyms) | Add synonym entries to a draft, one or many at once |
| [`PATCH /api/v1/imports/{import}/synonyms/{synonym}`](#change-synonym) | Change one synonym entry of a draft |
| [`DELETE /api/v1/imports/{import}/synonyms/{synonym}`](#delete-synonym) | Remove one synonym entry from a draft |
| [`POST /api/v1/imports/{import}/synonyms/check`](#check-synonym) | Say what an entry's words find today and what adding it to a draft would clash with |
| [`GET /api/v1/search-settings`](#show-search-settings) | Show how each type is searched now: its fields, typo settings and exempt attributes |
| [`GET /api/v1/imports/{import}/search-settings`](#show-draft-search-settings) | Show how each type of a draft is searched |
| [`PATCH /api/v1/imports/{import}/search-settings/{type}`](#change-search-settings) | Change how one type of a draft is searched |
| [`GET /api/v1/releases`](#list-releases) | List the releases, newest first |
| [`POST /api/v1/releases`](#create-release) | Store a release |
| [`GET /api/v1/releases/{release}`](#show-release) | Show a release with its files |
| [`POST /api/v1/releases/{release}/publish`](#publish-release) | Publish a release, or roll back to an earlier one |
| [`GET /api/v1/releases/{release}/publication`](#show-release-publication) | Show how publishing the release would go live, before it does |
| [`GET /api/v1/index-runs`](#list-index-runs) | List the index runs, newest first |
| [`POST /api/v1/index-runs`](#rebuild) | Index the current catalog with the published release again |
| [`GET /api/v1/index-runs/{index_run}`](#show-index-run) | Show an index run with its report |
| [`GET /api/v1/live`](#live) | Show what searches read now |
| [`PUT /api/v1/offers`](#change-offers) | Change prices and stock without sending the catalog |
| [`GET /api/v1/storage`](#show-storage) | Show what the storage keeps and the disk it takes |
| [`PATCH /api/v1/storage`](#change-storage) | Change how many earlier catalogs are kept |
| [`GET /api/v1/insights`](#show-insights) | Show what shoppers searched and clicked, what found nothing and the filters they chose |
| [`GET /api/v1/insights/campaigns`](#show-campaigns) | Show the views and clicks of each sponsored products' campaign |
| [`GET /api/v1/categories`](#list-categories) | Show the category tree of what is live |
| [`POST /api/v1/pages/settings`](#show-page-settings) | Show what a page shows and where each setting comes from |
| [`POST /api/v1/preview/search`](#preview-search) | Search as a shopper would, in any context and at any time, with the trace |
| [`POST /api/v1/preview/page`](#preview-page) | Open one of the shop's URLs as a shopper would, in any context and at any time |
| [`POST /api/v1/preview/compare`](#preview-compare) | Say why one hit of a preview sits above another |
| [`POST /api/v1/preview/find`](#preview-find) | Say why a product is not on a preview's page, or where it is |

## Replace the catalog

`PUT /api/v1/catalog`

The body is the whole catalog as the shop exported it, in any of the media types listed. It is kept byte for byte as a snapshot named by its content; the published release's feed.json says how its columns map, and a later release reads the same snapshot again. With a release published, an index run makes it searchable, and `next` says what happens.

### Body

file · required

Sent as `application/x-ndjson`, `text/csv`, `text/tab-separated-values`, `application/xml`, `application/vnd.openxmlformats-officedocument.spreadsheetml.sheet`, `application/json`, `application/gzip`, `application/octet-stream`.

### Answers

- `202` (object): The catalog is kept.
  
  - `snapshot` ([Snapshot](#Snapshot) · required): A catalog as it was uploaded, named by its content.
  
  - `run` ([IndexRun](#IndexRun)): The index run that makes it searchable; none before a release is published.
  
  - `next` (string · required): What happens next, as a sentence.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

- `413` ([problem](/docs/reference/problems#413)): The body is larger than the control plane accepts.

- `422` ([problem](/docs/reference/problems#422)): The body holds no catalog.

## Show the feed the catalog is fetched from, with its latest fetches

`GET /api/v1/catalog-source`

The feed URL, how it signs in without its secret, its schedule, when it is fetched next, and its last ten fetches, newest first, each with how it ended and why. `needs_attention` is set while the latest changed feed is held back or the last three fetches failed.

### Answers

- `200` (object): The catalog source.
  
  - `url` (string · required)
  
  - `authentication` (object): How the fetch signs in, without its secret; left out when it does not.
    
    How a catalog source signs in, as it is shown: its secret never is.
    
    - `basic` (kind: "basic"): HTTP basic authentication.
      
      - `username` (string · required)
    
    - `header` (kind: "header"): A header that carries a token, such as `Authorization` or `X-Api-Key`.
      
      - `name` (string · required)
  
  - `interval_minutes` (integer · required): How often the feed is fetched.
  
  - `on_change` (string · required): What a fetch does with a feed that changed.
    
    - `publish`: It goes live at once, unless it would remove half the live products or more.
    
    - `draft`: It waits as a draft import to review and publish.
  
  - `next_fetch_at` (string · required): When the schedule fetches next: at once after a fetch was asked for, otherwise one interval after the last one started.
  
  - `fetch_requested_at` (string): When a fetch was asked for that has not started yet.
  
  - `needs_attention` (boolean): The latest changed feed is held back, or the last three fetches failed; Overview lists the source then. Left out otherwise.
  
  - `fetches` ([array of CatalogFetch](#CatalogFetch) · required): The last ten fetches, newest first.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

- `404` ([problem](/docs/reference/problems#404)): There is none.

## Fetch the catalog from a feed URL on a schedule

`PUT /api/v1/catalog-source`

The control plane fetches the feed every `interval_minutes`, asking whether it changed since the last fetch. A feed that changed becomes an import and goes live as publishing it would, or waits as a draft when `on_change` is `draft`; one that would remove half the live products or more is held back as a draft to confirm. The same bytes again queue nothing. A new URL or new credentials are fetched at once. The credentials are kept encrypted and never answered; left out, the kept ones stay, and `null` removes them. A URL in a private, loopback or link-local network is refused at fetch time unless the stack allows it.

### Body

The feed to fetch the catalog from, and how.

- `url` (string · required): An `http` or `https` URL, without a user or password in it.

- `interval_minutes` (integer · 5 to 1440): How often to fetch it. Default: 60.

- `on_change` (string): What a feed that changed does. Default: `publish`.
  
  - `publish`: It goes live at once, unless it would remove half the live products or more.
  
  - `draft`: It waits as a draft import to review and publish.

- `authentication` (object or null): How to sign in, kept encrypted and sent only to the feed's own host. Left out, the kept credentials stay; `null` removes them.
  
  - `basic` (kind: "basic"): HTTP basic authentication.
    
    - `username` (string · required)
    
    - `password` (string · required)
  
  - `header` (kind: "header"): A header that carries a token. Its name holds letters, digits and hyphens.
    
    - `name` (string · required)
    
    - `value` (string · required)

### Answers

- `200` (object): The catalog source is changed.
  
  - `url` (string · required)
  
  - `authentication` (object): How the fetch signs in, without its secret; left out when it does not.
    
    How a catalog source signs in, as it is shown: its secret never is.
    
    - `basic` (kind: "basic"): HTTP basic authentication.
      
      - `username` (string · required)
    
    - `header` (kind: "header"): A header that carries a token, such as `Authorization` or `X-Api-Key`.
      
      - `name` (string · required)
  
  - `interval_minutes` (integer · required): How often the feed is fetched.
  
  - `on_change` (string · required): What a fetch does with a feed that changed.
    
    - `publish`: It goes live at once, unless it would remove half the live products or more.
    
    - `draft`: It waits as a draft import to review and publish.
  
  - `next_fetch_at` (string · required): When the schedule fetches next: at once after a fetch was asked for, otherwise one interval after the last one started.
  
  - `fetch_requested_at` (string): When a fetch was asked for that has not started yet.
  
  - `needs_attention` (boolean): The latest changed feed is held back, or the last three fetches failed; Overview lists the source then. Left out otherwise.
  
  - `fetches` ([array of CatalogFetch](#CatalogFetch) · required): The last ten fetches, newest first.

- `201` (object): The catalog source is set.
  
  - `url` (string · required)
  
  - `authentication` (object): How the fetch signs in, without its secret; left out when it does not.
    
    How a catalog source signs in, as it is shown: its secret never is.
    
    - `basic` (kind: "basic"): HTTP basic authentication.
      
      - `username` (string · required)
    
    - `header` (kind: "header"): A header that carries a token, such as `Authorization` or `X-Api-Key`.
      
      - `name` (string · required)
  
  - `interval_minutes` (integer · required): How often the feed is fetched.
  
  - `on_change` (string · required): What a fetch does with a feed that changed.
    
    - `publish`: It goes live at once, unless it would remove half the live products or more.
    
    - `draft`: It waits as a draft import to review and publish.
  
  - `next_fetch_at` (string · required): When the schedule fetches next: at once after a fetch was asked for, otherwise one interval after the last one started.
  
  - `fetch_requested_at` (string): When a fetch was asked for that has not started yet.
  
  - `needs_attention` (boolean): The latest changed feed is held back, or the last three fetches failed; Overview lists the source then. Left out otherwise.
  
  - `fetches` ([array of CatalogFetch](#CatalogFetch) · required): The last ten fetches, newest first.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

- `422` ([problem](/docs/reference/problems#422)): A setting is missing or out of range.

## Stop fetching the catalog from its feed URL

`DELETE /api/v1/catalog-source`

The source and its fetches go; the imports its fetches made stay in the history.

### Answers

- `200` (object): The source is removed, as it was.
  
  - `url` (string · required)
  
  - `authentication` (object): How the fetch signs in, without its secret; left out when it does not.
    
    How a catalog source signs in, as it is shown: its secret never is.
    
    - `basic` (kind: "basic"): HTTP basic authentication.
      
      - `username` (string · required)
    
    - `header` (kind: "header"): A header that carries a token, such as `Authorization` or `X-Api-Key`.
      
      - `name` (string · required)
  
  - `interval_minutes` (integer · required): How often the feed is fetched.
  
  - `on_change` (string · required): What a fetch does with a feed that changed.
    
    - `publish`: It goes live at once, unless it would remove half the live products or more.
    
    - `draft`: It waits as a draft import to review and publish.
  
  - `next_fetch_at` (string · required): When the schedule fetches next: at once after a fetch was asked for, otherwise one interval after the last one started.
  
  - `fetch_requested_at` (string): When a fetch was asked for that has not started yet.
  
  - `needs_attention` (boolean): The latest changed feed is held back, or the last three fetches failed; Overview lists the source then. Left out otherwise.
  
  - `fetches` ([array of CatalogFetch](#CatalogFetch) · required): The last ten fetches, newest first.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

- `404` ([problem](/docs/reference/problems#404)): There is none.

## Fetch the catalog source now

`POST /api/v1/catalog-source/fetch`

The schedule starts the fetch within seconds; `showCatalogSource` lists it once it has started, and how it ended once it has.

### Answers

- `202` (object): The fetch is asked for.
  
  - `url` (string · required)
  
  - `authentication` (object): How the fetch signs in, without its secret; left out when it does not.
    
    How a catalog source signs in, as it is shown: its secret never is.
    
    - `basic` (kind: "basic"): HTTP basic authentication.
      
      - `username` (string · required)
    
    - `header` (kind: "header"): A header that carries a token, such as `Authorization` or `X-Api-Key`.
      
      - `name` (string · required)
  
  - `interval_minutes` (integer · required): How often the feed is fetched.
  
  - `on_change` (string · required): What a fetch does with a feed that changed.
    
    - `publish`: It goes live at once, unless it would remove half the live products or more.
    
    - `draft`: It waits as a draft import to review and publish.
  
  - `next_fetch_at` (string · required): When the schedule fetches next: at once after a fetch was asked for, otherwise one interval after the last one started.
  
  - `fetch_requested_at` (string): When a fetch was asked for that has not started yet.
  
  - `needs_attention` (boolean): The latest changed feed is held back, or the last three fetches failed; Overview lists the source then. Left out otherwise.
  
  - `fetches` ([array of CatalogFetch](#CatalogFetch) · required): The last ten fetches, newest first.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

- `404` ([problem](/docs/reference/problems#404)): There is none.

## List the imports, newest first

`GET /api/v1/imports`

A page of imports; `links` and `meta` lead to the others. Every import keeps the release it went live with, so any one of them can go live again while its export is kept.

### Parameters

- `page` (integer · at least 1): The page, counted from 1. Default: 1.

- `per_page` (integer · 1 to 100): How many to a page. Default: 15.

### Answers

- `200` (object): The imports.
  
  - `data` ([array of Import](#Import) · required)
  
  - `links` ([PageLinks](#PageLinks) · required): The pages around this one, as URLs to fetch.
  
  - `meta` ([PageMeta](#PageMeta) · required): Where this page stands in the whole list.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

## Start an import: keep an export without making it live

`POST /api/v1/imports`

The body is the export as the shop wrote it, in any of the media types listed, kept byte for byte as a snapshot. Nothing goes live: inspect it, correct the files it is read with, then publish it. `PUT /api/v1/catalog` is the one-step path for automation that needs no look first.

### Parameters

- `name` (string): The file's name, such as `export.csv`, so the panel and the history can tell imports apart.

### Body

file · required

Sent as `application/x-ndjson`, `text/csv`, `text/tab-separated-values`, `application/xml`, `application/vnd.openxmlformats-officedocument.spreadsheetml.sheet`, `application/json`, `application/gzip`, `application/octet-stream`.

### Answers

- `201` (object): The export is kept as a draft import.
  
  - `import` ([Import](#Import) · required): An export on its way to live: the file as the shop wrote it, the release files it is read with, and once published, the release and the index run that make it live. Imports are never deleted, so every export that went live can go live again while its file is kept.
  
  - `next` (string · required): What to do next, as a sentence.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

- `413` ([problem](/docs/reference/problems#413)): The body is larger than the control plane accepts.

- `422` ([problem](/docs/reference/problems#422)): The body holds no export.

## Show an import with its files and its run

`GET /api/v1/imports/{import}`

Its state says where it stands; once published, `run` says how the index run goes.

### Parameters

- `import` (string · required)

### Answers

- `200` ([Import](#Import)): The import.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

- `404` ([problem](/docs/reference/problems#404)): There is none.

## Change the release files an import is read with

`PATCH /api/v1/imports/{import}`

Each named file replaces the import's own version of it, as its JSON object or as text; `null` drops it, so the published release's file applies again. The Query API checks the release they make together. Only an import that has not been published can change. `version` is the import's version you read: a draft changed since, by a person or an agent, refuses the write with 409 and the draft as it is now, so nobody overwrites another silently.

### Parameters

- `import` (string · required)

### Body

Release files to read an import with, such as `{ "files": { "feed.json": { "columns": { "Preis": "price" } } } }`. A file given as `null` is dropped, so the base release's applies again.

- `version` (string · required): The import's `version` as read; a draft that changed since refuses the write.

- `files` (object · required)

### Answers

- `200` ([Import](#Import)): The files are changed.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

- `404` ([problem](/docs/reference/problems#404)): There is none.

- `409` ([problem](/docs/reference/problems#draftconflict)): The draft changed since `version` was read, and `draft` is the draft as it is now; or it was published or discarded, and `draft` is left out.

- `422` ([problem](/docs/reference/problems#422)): The release the files make has violations.

- `502` ([problem](/docs/reference/problems#502)): The Query API could not check it.

## Discard an import that has not gone live

`DELETE /api/v1/imports/{import}`

The import leaves the list of drafts and stays in the history; the indexer's clean-up removes its export.

### Parameters

- `import` (string · required)

### Answers

- `200` ([Import](#Import)): The import is discarded.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

- `404` ([problem](/docs/reference/problems#404)): There is none.

- `409` ([problem](/docs/reference/problems#409)): The import was published.

## Show what the import makes of its export

`GET /api/v1/imports/{import}/inspection`

What the import makes of the export with its files: the format, every column with samples, where it goes and why, the products it becomes, the first of them as they would be indexed, and the rows that would be left out, grouped by cause. With `sample`, the products and problems cover the first rows only, which answers a large export faster.

### Parameters

- `import` (string · required)

- `sample` (integer · at least 1): Map only the first rows, which answers faster for a large export; the columns and the mapping still describe the whole file. Default: every row.

### Answers

- `200` (object): The inspection.
  
  - `feed` ([FeedReport](#FeedReport) · required): How the file was read and who placed its columns, with the columns whose values go nowhere.
  
  - `rows` (integer · required): Rows in the file, the header and blank rows not counted.
  
  - `sample` (integer): When the products, rejections and values cover the first rows only: how many it mapped. Left out when they cover the whole file. The columns and the mapping always describe the whole file.
  
  - `columns` (array of objects): Every column of the file, in the file's order; empty for OrbSearch's own JSON Lines.
    
    One column of an export: what it holds and where its values go.
    
    - `name` (string · required): The column's name as the header writes it.
    
    - `filled` (integer · required): Rows with a value in it.
    
    - `samples` (array of strings): Its first different values as written, up to five.
    
    - `mapping` (string or object): Where its values go; left out when they go nowhere.
    
    - `reason` (object · required): Why a column goes where it goes.
      
      - `file` (by: "file"): `feed.json` names it, by its name or by a pattern such as `Attribut_*`.
        
        - `pattern` (string)
      
      - `unmapped` (by: "unmapped"): `feed.json` does not name it, so its values are left out.
      
      - `alias` (by: "alias"): Its name is one Merchant Center or a common shop export gives the field, such as `artikelnummer` for `id`.
        
        - `alias` (string · required)
      
      - `definition` (by: "definition"): Its name is the code, a label or a source name of an attribute in `attributes.json`.
        
        - `attribute` (string · required): The code of an attribute definition, such as `color` or `seat_height`. The reserved words `any`, `all`, `not`, `category`, `brand`, `price`, `on_sale`, `availability`, `delivery_days` and `rating` cannot be attribute codes.
      
      - `regular_price` (by: "regular_price"): A German shop's price pair: struck through beside the shop's price, this column is the regular price.
        
        - `beside` (string · required)
      
      - `reduced_price` (by: "reduced_price"): A German shop's price pair: beside a struck-through price, the column a shop calls its price is the reduced one.
        
        - `beside` (string · required)
      
      - `prefix` (by: "prefix"): It shares its prefix with other columns, and each of them is an attribute.
        
        - `prefix` (string · required)
        
        - `columns` (integer · required)
      
      - `named_by` (by: "named_by"): It holds attribute values whose names stand in a sibling column, as WooCommerce and Shopify write them.
        
        - `column` (string · required)
      
      - `names_for` (by: "names_for"): It holds the attribute names for the values of another column.
        
        - `column` (string · required)
      
      - `names_missing` (by: "names_missing"): Its attribute names should stand in a column the file does not have, so its values are left out.
        
        - `column` (string · required)
      
      - `pairs` (by: "pairs"): Its cells hold several attributes as name and value pairs, such as "Farbe: Rot | Breite: 218 cm".
      
      - `name` (by: "name"): No alias knows it, so it is an attribute under a code made from its name.
      
      - `not_for_search` (by: "not_for_search"): Shipping, tax or ads data, or another column search does not use, such as `product_detail`'s section names.
      
      - `empty` (by: "empty"): No row fills it.
    
    - `proposed` (object): Where `feed.json` placed the column: where the import itself would send it, and why. Beside a merchant's change, it says what going back to the proposal means.
      
      The import's own proposal for a column: where it would go without `feed.json`, and why.
      
      - `mapping` (string or object): Left out when the import would leave its values out.
      
      - `reason` (object · required): Why a column goes where it goes.
        
        - `file` (by: "file"): `feed.json` names it, by its name or by a pattern such as `Attribut_*`.
          
          - `pattern` (string)
        
        - `unmapped` (by: "unmapped"): `feed.json` does not name it, so its values are left out.
        
        - `alias` (by: "alias"): Its name is one Merchant Center or a common shop export gives the field, such as `artikelnummer` for `id`.
          
          - `alias` (string · required)
        
        - `definition` (by: "definition"): Its name is the code, a label or a source name of an attribute in `attributes.json`.
          
          - `attribute` (string · required): The code of an attribute definition, such as `color` or `seat_height`. The reserved words `any`, `all`, `not`, `category`, `brand`, `price`, `on_sale`, `availability`, `delivery_days` and `rating` cannot be attribute codes.
        
        - `regular_price` (by: "regular_price"): A German shop's price pair: struck through beside the shop's price, this column is the regular price.
          
          - `beside` (string · required)
        
        - `reduced_price` (by: "reduced_price"): A German shop's price pair: beside a struck-through price, the column a shop calls its price is the reduced one.
          
          - `beside` (string · required)
        
        - `prefix` (by: "prefix"): It shares its prefix with other columns, and each of them is an attribute.
          
          - `prefix` (string · required)
          
          - `columns` (integer · required)
        
        - `named_by` (by: "named_by"): It holds attribute values whose names stand in a sibling column, as WooCommerce and Shopify write them.
          
          - `column` (string · required)
        
        - `names_for` (by: "names_for"): It holds the attribute names for the values of another column.
          
          - `column` (string · required)
        
        - `names_missing` (by: "names_missing"): Its attribute names should stand in a column the file does not have, so its values are left out.
          
          - `column` (string · required)
        
        - `pairs` (by: "pairs"): Its cells hold several attributes as name and value pairs, such as "Farbe: Rot | Breite: 218 cm".
        
        - `name` (by: "name"): No alias knows it, so it is an attribute under a code made from its name.
        
        - `not_for_search` (by: "not_for_search"): Shipping, tax or ads data, or another column search does not use, such as `product_detail`'s section names.
        
        - `empty` (by: "empty"): No row fills it.
  
  - `mapping` ([object](/docs/reference/catalog/feed) · required): The mapping as `feed.json` holds it: the release's own, or the derived one, ready to be saved and corrected.
  
  - `defaults` ([Defaults](#Defaults)): The release files the release leaves out, derived from the export, each setting with its reason. Attribute definitions, types and channels describe the whole file, except an attribute a correction changed after the export's first look, which the rows mapped describe; facets, sorting and ranking describe the rows mapped.
  
  - `products` (integer · required): Products the rows become.
  
  - `variants` (integer · required): Their variants; a product without variants counts none.
  
  - `categories` (integer · required): Categories made from the category paths.
  
  - `preview` ([array of objects](/docs/reference/catalog/entity) · required): The first products as they would be indexed, their values read as their definitions say.
  
  - `tiles` (array of objects): The same products as a search answers them in the first channel and its first locale: the hits a storefront draws as tiles. Empty while the release has no channel.
    
    One result tile.
    
    - `entity` (string · required): An entity named with its type, `type:id`, such as `product:SOFA-LUND-3`.
    
    - `variant` (string): The variant the tile shows, when the listing grain is finer than the product or the shopper's choices on variant-level values pick one, such as the grey variant of a sofa under a grey filter.
    
    - `fields` (object · required): The type's result fields, in the request's locale and channel.
    
    - `sponsored` (object): A rule's paid pin placed it here: a storefront labels the tile as an ad and names the campaign in the tile's clicks and views.
      
      The campaign a paid placement belongs to: `{ "campaign": "Michelin spring" }`.
      
      - `campaign` (string · required): The merchant's name for it, which the campaign report counts by.
  
  - `details` (array of objects): Every product detail shoppers could meet: the attributes the products carry and the fields every shop filters by, each a filter, found by search or not used, as the release completed with the derived files makes it. The filters come first, in the order pages show them; their values cover the sample, as the products do.
    
    A product detail as shoppers meet it: what it is for, what else it could be, and why the import chose as it did.
    
    - `field` (string · required): An attribute's code, or one of the fields every shop has: `category`, `brand`, `price`, `availability`, `delivery_days`, `on_sale` and `rating`.
    
    - `label` (string): Its name in the shop's first language, as shoppers read it: an attribute's label, a field every shop has by the built-in words such as "Preis". The panel names the fields every shop has in the merchant's own language.
    
    - `column` (string): The column it comes from, as the header writes it.
    
    - `products` (integer · required): Products that carry it, on themselves or on a variant.
    
    - `values` (object): An attribute's values, read as its definition says.
      
      - `options` (as: "options"): Values a shopper ticks, the most common first, each with how many products carry it. An attribute with color groups shows its groups with their swatches; values no group took follow in `ungrouped`.
        
        - `values` ([array of FacetValue](#FacetValue) · required)
        
        - `ungrouped` ([array of FacetValue](#FacetValue))
      
      - `range` (as: "range"): Numbers, quantities or ranges a shopper narrows: the lowest and highest, in the attribute's unit.
        
        - `min` (number · required)
        
        - `max` (number · required)
        
        - `unit` (string): A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
          
          - `mm`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
          
          - `cm`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
          
          - `m`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
          
          - `in`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
          
          - `ft`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
          
          - `g`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
          
          - `kg`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
          
          - `lb`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
          
          - `oz`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
          
          - `ml`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
          
          - `l`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
          
          - `w`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
          
          - `kw`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
          
          - `wh`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
          
          - `kwh`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
          
          - `mah`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
          
          - `v`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
          
          - `lm`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
          
          - `kelvin`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
          
          - `celsius`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
          
          - `hz`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
          
          - `mb`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
          
          - `gb`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
          
          - `tb`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
          
          - `day`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
          
          - `month`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
          
          - `year`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `toggle` (as: "toggle"): Yes or no.
        
        - `yes` (integer · required)
        
        - `no` (integer · required)
      
      - `text` (as: "text"): Text, dates and identifiers, which nobody ticks: its first values as written. An attribute attributes.json does not define is kept as written and shows here.
        
        - `samples` (array of strings · required)
        
        - `defined` (boolean): attributes.json defines it.
    
    - `use` (string · required): What it is for now.
      
      - `filter`: Shoppers narrow the products by its values.
      
      - `search`: Its words find the products when shoppers type them.
      
      - `none`: Neither.
    
    - `choices` (array of strings · required): What it can be for: the category is always a filter, the other fields every shop has are never searched, and text, codes and dates make no filter.
      
      - `filter`: Shoppers narrow the products by its values.
      
      - `search`: Its words find the products when shoppers type them.
      
      - `none`: Neither.
    
    - `facet` (string or object): The facet `categories.json` lists for it as a filter, in the shape the import gives it, such as the price's buckets or the color groups as swatches. Left out when it can be no filter.
    
    - `look` (string): How a shop's filter column draws it as a filter; left out when it can be no filter.
      
      - `tree`: The category tree.
      
      - `list`: Values to tick.
      
      - `swatches`: Colors as swatches.
      
      - `tiles`: Sizes as tiles.
      
      - `range`: A range of numbers or its buckets.
      
      - `toggle`: Yes or no.
      
      - `stars`: Stars from a rating.
    
    - `unchosen` (object): Why the import would not make it a filter of search pages by itself, though it can be one.
      
      Why the import would not make a detail a filter of search pages by itself. A merchant may still choose it; the reason says what shoppers who use it meet.
      
      - `rare` (by: "rare"): Fewer than half the products carry it, so shoppers who use it hide the rest.
        
        - `products` (integer · required)
        
        - `of` (integer · required)
      
      - `values` (by: "values"): More values than a filter lists, about fifty.
        
        - `values` (integer · required)
      
      - `single` (by: "single"): One value only, so there is nothing to choose.
      
      - `count` (by: "count"): A number without a unit that is no short list of whole values, such as a sales count or a score.
      
      - `variant_number` (by: "variant_number"): A number that differs between variants, which only buckets count exactly.
      
      - `suggested` (by: "suggested"): The decision model judged it no filter, though the import's own test would make it one.
    
    - `categories` (integer): A filter only of this many category pages, where most products carry it, and not of search pages.
    
    - `buckets` (array of strings): How shoppers read the filter's ranges in the shop's first language, in the facet's order, such as "bis 10 €"; empty where the filter lists values.
    
    - `suggested` (string): What the decision model judged it is for, as `feed.json`'s `uses` holds it.
      
      - `filter`: Shoppers narrow the products by its values.
      
      - `search`: Its words find the products when shoppers type them.
      
      - `none`: Neither.
  
  - `violations` (array of objects): What the release, completed with what this export derives, does not hold, such as a filter `categories.json` names over a column this export no longer has. The index run would fail with the same sentences.
    
    One thing that is wrong with the input, and where.
    
    - `file` (string): The file, such as `rules.json`, when the input is a release.
    
    - `pointer` (string · required): A JSON pointer to the value, such as `/rules/3/then/pin/0/entity`.
    
    - `message` (string · required): What is wrong, as a sentence.
  
  - `rejected` (integer · required): Rows that would be left out.
  
  - `rejections` ([array of RejectionGroup](#RejectionGroup)): Those rows grouped by what is wrong, the most common first.
  
  - `values` ([ValuesReport](#ValuesReport)): What the import would make of the attribute values.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

- `404` ([problem](/docs/reference/problems#404)): There is none.

- `422` ([problem](/docs/reference/problems#422)): The export cannot be read, or the release has violations.

- `502` ([problem](/docs/reference/problems#502)): The Query API could not inspect it.

## Show where a decision model would send the export's columns

`GET /api/v1/imports/{import}/suggestions`

For each column that holds values, the field, attribute or signal a decision model behind the AI gateway chose for it, with its probability. The model is asked once per import and the answer is kept, so asking again costs nothing. A suggestion changes nothing until it is chosen: send the column's new place in `feed.json` with `changeImport`. Off while the Query API has no AI gateway key.

### Parameters

- `import` (string · required)

### Answers

- `200` (object): The suggestions.
  
  - `model` (string · required): The model that answered, as the AI gateway names it, such as `typesafe-ai/jev`.
  
  - `columns` (array of objects · required): One per column that holds values, in the file's order.
    
    Where the model would send one column, and how probable it finds that.
    
    - `column` (string · required): The column's name as the header writes it.
    
    - `target` (string · required): The model's choice among the fields, the release's attributes and signals, an attribute of the column's own, and `ignore`.
    
    - `probability` (number · at most 1 · required): The model's probability for its choice.
    
    - `taken` (boolean): Taken into the mapping without asking: the model is nearly certain, and the import could only guess the column, placed it by a shared prefix or left it out, or only a column's name chose the field. A column whose field another column took is taken to the model's choice for it, so no field is filled twice.
  
  - `mapping` ([object](/docs/reference/catalog/feed)): The import's mapping with the taken suggestions in it, as `feed.json` holds it; left out when none was taken.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

- `404` ([problem](/docs/reference/problems#404)): There is none.

- `422` ([problem](/docs/reference/problems#422)): The export cannot be read, or the release has violations.

- `502` ([problem](/docs/reference/problems#502)): The Query API or the AI gateway did not answer.

- `503` ([problem](/docs/reference/problems#503)): Mapping suggestions are off: the Query API has no AI gateway key.

## Show what making an import live changes

`GET /api/v1/imports/{import}/changes`

The import's export and files against what searches read now: the products added and removed, as each export names them, and the attributes and filters new and gone. Both exports are read whole, so a large one takes a few seconds per gigabyte. When the draft removes half the live products or more, `products.needs_confirmation` is set and publishing it needs `removing`.

### Parameters

- `import` (string · required)

### Answers

- `200` (object): The changes.
  
  - `products` (object · required): Products as the exports name them: an export's product is its group, or the row's id where it has none. A row left out by a problem still names its product, so the problems are counted apart.
    
    - `draft` (integer · required): Products the import's export names.
    
    - `live` (integer · required): Products the live export names; 0 when nothing is live.
    
    - `added` (integer · required): In the draft, not live.
    
    - `removed` (integer · required): Live, not in the draft.
    
    - `added_examples` (array of strings): The first ids added, up to `LISTED_CHANGES`.
    
    - `removed_examples` (array of strings): The first ids removed, up to `LISTED_CHANGES`.
    
    - `needs_confirmation` (boolean): The draft removes so large a share of the live products that publishing it needs the number confirmed: a broken export must not empty a shop.
  
  - `attributes` (object · required): Attributes the export's columns go to by name, new and gone; attributes named inside cells, such as name and value pairs, are not compared.
    
    What a draft adds and what it removes, against what is live; both lists are always written.
    
    - `added` (array of strings · required)
    
    - `removed` (array of strings · required)
  
  - `facets` (object · required): The filters of search pages, as `categories.json` lists them.
    
    What a draft adds and what it removes, against what is live; both lists are always written.
    
    - `added` (array of strings · required)
    
    - `removed` (array of strings · required)

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

- `404` ([problem](/docs/reference/problems#404)): There is none.

- `422` ([problem](/docs/reference/problems#422)): An export cannot be read, or the release has violations.

- `502` ([problem](/docs/reference/problems#502)): The Query API could not compare them.

## Make an import live, or go back to an earlier one

`POST /api/v1/imports/{import}/publish`

Stores the release its files make, publishes it and queues an index run with its export; `run` says how it goes. Publishing an import that was live before is how a merchant goes back to it. An import that would remove half the live products or more is published only with `removing` set to the number `showImportChanges` names, because a broken export must not empty a shop.

### Parameters

- `import` (string · required)

- `removing` (integer): How many live products the export leaves out, as `showImportChanges` counts them: the confirmation that an import removing half the live products or more is meant to.

- `version` (string): The draft's `version` as reviewed, so what goes live is what was looked at: a draft that changed since is refused. Default: the draft as it is.

### Answers

- `202` (object): The import is published.
  
  - `import` ([Import](#Import) · required): An export on its way to live: the file as the shop wrote it, the release files it is read with, and once published, the release and the index run that make it live. Imports are never deleted, so every export that went live can go live again while its file is kept.
  
  - `next` (string · required): What happens next, as a sentence.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

- `404` ([problem](/docs/reference/problems#404)): There is none.

- `409` ([problem](/docs/reference/problems#draftconflict)): The draft changed since `version` was read, or while its release was built, and `draft` is the draft as it is now; or the import was discarded, is going live already, its export was removed, or it removes half the live products or more and `removing` does not name how many, and `draft` is left out.

- `422` ([problem](/docs/reference/problems#422)): The release the files make has violations.

- `502` ([problem](/docs/reference/problems#502)): The Query API could not check it.

## Show how publishing the import would go live, before it does

`GET /api/v1/imports/{import}/publication`

What publishing the import would do, decided by the decision the indexer takes: `course` says whether it goes live at once (a switch), after settings the engine applies without reindexing, or by a rebuild of the indexes, and why, as data and as a sentence. For a rebuild, `estimate_seconds` is about how long it takes, from the last rebuild; the shop keeps answering with the live release meanwhile. Nothing is published.

### Parameters

- `import` (string · required)

### Answers

- `200` (object): How publishing would go live.
  
  - `course` ([Course](#Course) · required): The way a release goes live and why, as data and as a sentence.
  
  - `estimate_seconds` (integer): For a rebuild: about how many seconds it takes, from the time of the last rebuild. It grows with the catalog, so a much larger catalog takes longer. Left out for any other way, and before a first rebuild.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

- `404` ([problem](/docs/reference/problems#404)): There is none.

- `409` ([problem](/docs/reference/problems#409)): There is no catalog yet, so nothing can be indexed before one is uploaded.

- `422` ([problem](/docs/reference/problems#422)): The draft files make a release with violations; each names its file, a JSON pointer and what is wrong.

- `502` ([problem](/docs/reference/problems#502)): The Query API could not be reached.

## List the live rules in order, each with its state and its conflicts

`GET /api/v1/rules`

Every rule of the release searches read, in rule order. Each has what it does in one line, its state at `time` (active, scheduled, expired, disabled, or dormant because everything it acts on left the catalog), the conflicts with the rules above it, the entities it names that the catalog no longer holds, and the fields an editor sets. A rule the fields cannot express yet comes with its JSON, read only. States and conflicts are data with parameters, and a sentence that says the same, written once by the Query API.

### Parameters

- `channel` (string): The channel the catalog is read in. Default: the release's first channel.

- `locale` (string): The locale the products are named in. Default: the channel's first locale.

- `time` (string): The time the states are as at, so a scheduled rule can be seen on the day it starts. Default: now.

### Answers

- `200` ([RuleList](#RuleList)): The rules.

- `400` ([problem](/docs/reference/problems#400)): The channel, locale or time cannot be answered, such as a channel the release lacks.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

- `502` ([problem](/docs/reference/problems#502)): The Query API could not be reached.

- `503` ([problem](/docs/reference/problems#503)): Nothing is searchable yet, or the engine is unreachable.

```sh title="Terminal"
curl -s -H "Authorization: Bearer $key" $api/rules | jq '[.rules[] | {id, state, summary}][:3]'
```

```json title="Answer: 200 · 11 ms · release b25a6aaa"
[
  {
    "id": "home/sofa-sale",
    "state": {
      "id": "active",
      "sentence": "Active."
    },
    "summary": "Places banner \"Sofas im Angebot\" on top, places teaser \"Sessel aus Leder, Samt und Stoff\" at 4 on \"Sofas\""
  },
  {
    "id": "home/out-of-stock-last",
    "state": {
      "id": "disabled",
      "sentence": "Switched off."
    },
    "summary": "Buries availability is \"out_of_stock\" (strong)"
  },
  {
    "id": "home/guides-for-questions",
    "state": {
      "id": "disabled",
      "sentence": "Switched off."
    },
    "summary": "Orders the sections content, product, category when query starts with \"wie\" or \"welche\" or \"welcher\" or \"welches\" or \"how\" or \"which\" and on search"
  }
]
```

## List a draft's rules in order, each with its state and its conflicts

`GET /api/v1/imports/{import}/rules`

The same answer for the rules a draft makes, with the draft's `version` to write on. A draft that changes no rules lists the live ones.

### Parameters

- `import` (string · required)

- `channel` (string): The channel the catalog is read in. Default: the release's first channel.

- `locale` (string): The locale the products are named in. Default: the channel's first locale.

- `time` (string): The time the states are as at, so a scheduled rule can be seen on the day it starts. Default: now.

### Answers

- `200` (object): The draft's rules.
  
  - `version` (string · required): The draft's version this answer is of; the next write names it.
  
  - `rules` ([RuleList](#RuleList) · required): The rules of a release in precedence order: the first rule is the highest.
  
  - `rule` (string): After a write: the rule created, changed or moved; left out after a delete and in a list.

- `400` ([problem](/docs/reference/problems#400)): The channel, locale or time cannot be answered, such as a channel the release lacks.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

- `404` ([problem](/docs/reference/problems#404)): There is none.

- `422` ([problem](/docs/reference/problems#422)): The draft files make a release with violations; each names its file, a JSON pointer and what is wrong.

- `502` ([problem](/docs/reference/problems#502)): The Query API could not be reached.

- `503` ([problem](/docs/reference/problems#503)): Nothing is searchable yet, or the engine is unreachable.

## Add a rule to a draft

`POST /api/v1/imports/{import}/rules`

Adds one rule through its fields; the first place in the order unless `position` says another. The Query API makes the rule, writes `rules.json` and checks the release as for `changeImport`, so violations come back with their JSON pointers. The answer is the draft's rules after the write.

### Parameters

- `import` (string · required)

### Body

A rule to add and the draft version it is written on.

- `version` (string · required): The version of a draft: it changes with every change of the draft's release files, and with the release the draft builds on. A write names the version it read, and is refused when the draft has moved on. Treat it as opaque.

- `id` (string): The rule's id. Default: made from the name, and made unique.

- `name` (string): The rule's name, one line up to 200 characters. Default: what the rule does, in a sentence.

- `enabled` (boolean): Default: on.

- `position` (integer): Its place in the order, counted from 1; a number past the end puts it last. Default: first, since a merchant's new rule outranks the older ones.

- `fields` ([RuleFields](#RuleFields) · required): The fields of a rule an editor sets.

### Answers

- `201` (object): The rule is added.
  
  - `version` (string · required): The draft's version this answer is of; the next write names it.
  
  - `rules` ([RuleList](#RuleList) · required): The rules of a release in precedence order: the first rule is the highest.
  
  - `rule` (string): After a write: the rule created, changed or moved; left out after a delete and in a list.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

- `404` ([problem](/docs/reference/problems#404)): There is none.

- `409` ([problem](/docs/reference/problems#draftconflict)): The draft changed since `version` was read, and `draft` is the draft as it is now; or it was published or discarded, and `draft` is left out.

- `422` ([problem](/docs/reference/problems#422)): The write has violations, or the release it makes does; each names a JSON pointer and what is wrong. A change of fields to a rule they cannot express is refused here.

- `502` ([problem](/docs/reference/problems#502)): The Query API could not be reached.

## Change one rule of a draft

`PATCH /api/v1/imports/{import}/rules/{rule}`

Changes the name, whether it is on, or its fields, all of them at once. A rule the fields cannot express yet keeps its name and switch changeable, and its fields are changed through the draft's files with `changeImport`. A rule id may hold slashes, which are sent as they are: `/api/v1/imports/3/rules/home/out-of-stock-last`.

### Parameters

- `import` (string · required)

- `rule` (string · required)

### Body

A change of one rule and the draft version it is written on.

- `version` (string · required): The version of a draft: it changes with every change of the draft's release files, and with the release the draft builds on. A write names the version it read, and is refused when the draft has moved on. Treat it as opaque.

- `name` (string)

- `enabled` (boolean)

- `fields` ([RuleFields](#RuleFields)): The new fields, all of them: the rule's condition, effects and window are replaced. Refused for a rule the fields cannot express, since the change would drop what they leave out.

### Answers

- `200` (object): The draft's rules after the write.
  
  - `version` (string · required): The draft's version this answer is of; the next write names it.
  
  - `rules` ([RuleList](#RuleList) · required): The rules of a release in precedence order: the first rule is the highest.
  
  - `rule` (string): After a write: the rule created, changed or moved; left out after a delete and in a list.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

- `404` ([problem](/docs/reference/problems#404)): There is none.

- `409` ([problem](/docs/reference/problems#draftconflict)): The draft changed since `version` was read, and `draft` is the draft as it is now; or it was published or discarded, and `draft` is left out.

- `422` ([problem](/docs/reference/problems#422)): The write has violations, or the release it makes does; each names a JSON pointer and what is wrong. A change of fields to a rule they cannot express is refused here.

- `502` ([problem](/docs/reference/problems#502)): The Query API could not be reached.

## Remove one rule from a draft

`DELETE /api/v1/imports/{import}/rules/{rule}`

Removes the rule from the draft. Publishing the draft removes it from searches; an earlier release still holds it.

### Parameters

- `import` (string · required)

- `rule` (string · required)

- `version` (string): The draft's `version` as read.

### Answers

- `200` (object): The draft's rules after the write.
  
  - `version` (string · required): The draft's version this answer is of; the next write names it.
  
  - `rules` ([RuleList](#RuleList) · required): The rules of a release in precedence order: the first rule is the highest.
  
  - `rule` (string): After a write: the rule created, changed or moved; left out after a delete and in a list.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

- `404` ([problem](/docs/reference/problems#404)): There is none.

- `409` ([problem](/docs/reference/problems#draftconflict)): The draft changed since `version` was read, and `draft` is the draft as it is now; or it was published or discarded, and `draft` is left out.

- `422` ([problem](/docs/reference/problems#422)): The write has violations, or the release it makes does; each names a JSON pointer and what is wrong. A change of fields to a rule they cannot express is refused here.

- `502` ([problem](/docs/reference/problems#502)): The Query API could not be reached.

## Move one rule of a draft to another place in the order

`PUT /api/v1/imports/{import}/rules/{rule}/position`

Puts the rule at `position` in the order; the rules between shift by one. Where two effects exclude each other, the higher rule wins, so the order is precedence.

### Parameters

- `import` (string · required)

- `rule` (string · required)

### Body

A move of one rule and the draft version it is written on.

- `version` (string · required): The version of a draft: it changes with every change of the draft's release files, and with the release the draft builds on. A write names the version it read, and is refused when the draft has moved on. Treat it as opaque.

- `position` (integer · at least 1 · required): Its new place, counted from 1; a number past the end puts it last.

### Answers

- `200` (object): The draft's rules after the write.
  
  - `version` (string · required): The draft's version this answer is of; the next write names it.
  
  - `rules` ([RuleList](#RuleList) · required): The rules of a release in precedence order: the first rule is the highest.
  
  - `rule` (string): After a write: the rule created, changed or moved; left out after a delete and in a list.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

- `404` ([problem](/docs/reference/problems#404)): There is none.

- `409` ([problem](/docs/reference/problems#draftconflict)): The draft changed since `version` was read, and `draft` is the draft as it is now; or it was published or discarded, and `draft` is left out.

- `422` ([problem](/docs/reference/problems#422)): The write has violations, or the release it makes does; each names a JSON pointer and what is wrong. A change of fields to a rule they cannot express is refused here.

- `502` ([problem](/docs/reference/problems#502)): The Query API could not be reached.

## List the live synonyms of every language

`GET /api/v1/synonyms`

Every synonym entry of the release searches read, by language: groups of words that mean the same, one-way entries, and words never merged. Each has its id, its words as the engine reads them, what it does in one line, and what it clashes with, as data and a sentence written once by the Query API. `locales` lists the languages the channels serve, the shop's first.

### Answers

- `200` ([SynonymList](#SynonymList)): The synonyms.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

- `502` ([problem](/docs/reference/problems#502)): The Query API could not be reached.

- `503` ([problem](/docs/reference/problems#503)): Nothing is searchable yet.

```sh title="Terminal"
curl -s -H "Authorization: Bearer $key" $api/synonyms \
  | jq '{locales, de: [.dictionaries[] | select(.locale == "de") | .entries[:2][] | {id, summary}]}'
```

```json title="Answer: 200 · 26 ms"
{
  "locales": [
    "de",
    "en"
  ],
  "de": [
    {
      "id": "de/groups/0",
      "summary": "sofa and couch find each other."
    },
    {
      "id": "de/groups/1",
      "summary": "zweisitzer and 2-sitzer find each other."
    }
  ]
}
```

## List a draft's synonyms of every language

`GET /api/v1/imports/{import}/synonyms`

The same answer for the synonyms a draft holds, with the draft's `version` to write on. A draft that changes no synonyms lists the live ones.

### Parameters

- `import` (string · required)

### Answers

- `200` (object): The draft's synonyms.
  
  - `version` (string · required): The draft's version this answer is of; the next write names it.
  
  - `synonyms` ([SynonymList](#SynonymList) · required): Every language's synonyms.
  
  - `written` (array of strings): After a write: the entries added or changed, in the order sent.
  
  - `refused` ([array of RefusedSynonym](#RefusedSynonym)): After an add: the entries that clash and were not written, each with why.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

- `404` ([problem](/docs/reference/problems#404)): There is none.

- `422` ([problem](/docs/reference/problems#422)): The draft's synonyms.json cannot be read; change it through the draft's files.

- `502` ([problem](/docs/reference/problems#502)): The Query API could not be reached.

- `503` ([problem](/docs/reference/problems#503)): Nothing is searchable yet.

## Add synonym entries to a draft, one or many at once

`POST /api/v1/imports/{import}/synonyms`

Adds entries to one language, such as `{ "kind": "group", "words": ["couch", "sofa"] }`, one or up to [`synonyms_per_call`](/docs/reference/limits#synonyms_per_call) at once, as pasting lines does. Words are trimmed, lowercased and kept once. An entry that would put a word in a second group, start a second one-way entry from the same word, or merge words a `never` entry keeps apart is refused, naming the entry it clashes with so the word can be added there; `despite_never` writes the last kind anyway. The others are written, and the answer lists both. Synonyms go live as settings, without a rebuild.

### Parameters

- `import` (string · required)

### Body

Synonym entries to add to one language of a draft, and the version they are written on.

- `version` (string · required): The version of a draft: it changes with every change of the draft's release files, and with the release the draft builds on. A write names the version it read, and is refused when the draft has moved on. Treat it as opaque.

- `locale` (string · required): The language, such as `de`: the first of the list's `locales` is the shop's.

- `entries` (array of objects · 1 to 1000 items · required): One entry of a language's synonyms.
  
  - `group` (kind: "group"): Words that mean the same, each way round, such as `["couch", "sofa"]`. A word or phrase is in one group at most.
    
    - `words` (array of strings · required)
  
  - `one_way` (kind: "one_way"): A word that also finds others, but not the other way round: `läufer` finds `teppich`. A word starts one such entry at most.
    
    - `from` (string · required)
    
    - `to` (array of strings · required)
  
  - `never` (kind: "never"): Words that look alike but must never be merged, such as `["sessel", "sofa"]`. They change no search; an entry that would merge them is refused unless the write says `despite_never`.
    
    - `words` (array of strings · required)

- `despite_never` (boolean): Writes an entry that merges words a `never` entry keeps apart, which is refused otherwise.

### Answers

- `201` (object): Entries are added; `refused` lists those that clash.
  
  - `version` (string · required): The draft's version this answer is of; the next write names it.
  
  - `synonyms` ([SynonymList](#SynonymList) · required): Every language's synonyms.
  
  - `written` (array of strings): After a write: the entries added or changed, in the order sent.
  
  - `refused` ([array of RefusedSynonym](#RefusedSynonym)): After an add: the entries that clash and were not written, each with why.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

- `404` ([problem](/docs/reference/problems#404)): There is none.

- `409` ([problem](/docs/reference/problems#draftconflict)): The draft changed since `version` was read, and `draft` is the draft as it is now; or it was published or discarded, and `draft` is left out.

- `422` ([problem](/docs/reference/problems#synonymsrefused)): Nothing is written: every entry clashes, and `refused` says why for each; or the release the write makes has violations, each with a JSON pointer.

- `502` ([problem](/docs/reference/problems#502)): The Query API could not be reached.

## Change one synonym entry of a draft

`PATCH /api/v1/imports/{import}/synonyms/{synonym}`

Replaces the entry's words, checked as an add checks them. An entry id holds slashes, which are sent as they are: `/api/v1/imports/3/synonyms/de/groups/0`. An entry that changes its kind moves after the entries of its new kind, and the answer names its new id.

### Parameters

- `import` (string · required)

- `synonym` (string · required)

### Body

An entry's new words and the draft version they are written on.

- `version` (string · required): The version of a draft: it changes with every change of the draft's release files, and with the release the draft builds on. A write names the version it read, and is refused when the draft has moved on. Treat it as opaque.

- `entry` (object · required): One entry of a language's synonyms.
  
  - `group` (kind: "group"): Words that mean the same, each way round, such as `["couch", "sofa"]`. A word or phrase is in one group at most.
    
    - `words` (array of strings · required)
  
  - `one_way` (kind: "one_way"): A word that also finds others, but not the other way round: `läufer` finds `teppich`. A word starts one such entry at most.
    
    - `from` (string · required)
    
    - `to` (array of strings · required)
  
  - `never` (kind: "never"): Words that look alike but must never be merged, such as `["sessel", "sofa"]`. They change no search; an entry that would merge them is refused unless the write says `despite_never`.
    
    - `words` (array of strings · required)

- `despite_never` (boolean): Writes an entry that merges words a `never` entry keeps apart, which is refused otherwise.

### Answers

- `200` (object): The draft's synonyms after the write.
  
  - `version` (string · required): The draft's version this answer is of; the next write names it.
  
  - `synonyms` ([SynonymList](#SynonymList) · required): Every language's synonyms.
  
  - `written` (array of strings): After a write: the entries added or changed, in the order sent.
  
  - `refused` ([array of RefusedSynonym](#RefusedSynonym)): After an add: the entries that clash and were not written, each with why.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

- `404` ([problem](/docs/reference/problems#404)): There is none.

- `409` ([problem](/docs/reference/problems#draftconflict)): The draft changed since `version` was read, and `draft` is the draft as it is now; or it was published or discarded, and `draft` is left out.

- `422` ([problem](/docs/reference/problems#synonymsrefused)): Nothing is written: every entry clashes, and `refused` says why for each; or the release the write makes has violations, each with a JSON pointer.

- `502` ([problem](/docs/reference/problems#502)): The Query API could not be reached.

## Remove one synonym entry from a draft

`DELETE /api/v1/imports/{import}/synonyms/{synonym}`

Removes the entry from the draft; the entries after it of its kind move up one place, so their ids change and the next write reads the list again.

### Parameters

- `import` (string · required)

- `synonym` (string · required)

- `version` (string): The draft's `version` as read.

### Answers

- `200` (object): The draft's synonyms after the write.
  
  - `version` (string · required): The draft's version this answer is of; the next write names it.
  
  - `synonyms` ([SynonymList](#SynonymList) · required): Every language's synonyms.
  
  - `written` (array of strings): After a write: the entries added or changed, in the order sent.
  
  - `refused` ([array of RefusedSynonym](#RefusedSynonym)): After an add: the entries that clash and were not written, each with why.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

- `404` ([problem](/docs/reference/problems#404)): There is none.

- `409` ([problem](/docs/reference/problems#draftconflict)): The draft changed since `version` was read, and `draft` is the draft as it is now; or it was published or discarded, and `draft` is left out.

- `422` ([problem](/docs/reference/problems#synonymsrefused)): Nothing is written: every entry clashes, and `refused` says why for each; or the release the write makes has violations, each with a JSON pointer.

- `502` ([problem](/docs/reference/problems#502)): The Query API could not be reached.

## Say what an entry's words find today and what adding it to a draft would clash with

`POST /api/v1/imports/{import}/synonyms/check`

For an entry being typed: how many results the search page lists for each word now, searched with the live release in one engine call, and what adding it to the draft would clash with, such as the group a word is in already. Nothing is written, and the draft is not indexed, so the counts are those of the live synonyms.

### Parameters

- `import` (string · required)

### Body

An entry being typed, to check before it is written.

- `locale` (string · required): A BCP 47 language tag such as `de`, `de-CH` or `en`. A locale falls back along its tag: `de-CH` to `de`.

- `channel` (string): The channel the words are searched in. Default: the first channel that serves a locale reading this language's synonyms, such as `de-CH` for `de`.

- `entry` (object · required): One entry of a language's synonyms.
  
  - `group` (kind: "group"): Words that mean the same, each way round, such as `["couch", "sofa"]`. A word or phrase is in one group at most.
    
    - `words` (array of strings · required)
  
  - `one_way` (kind: "one_way"): A word that also finds others, but not the other way round: `läufer` finds `teppich`. A word starts one such entry at most.
    
    - `from` (string · required)
    
    - `to` (array of strings · required)
  
  - `never` (kind: "never"): Words that look alike but must never be merged, such as `["sessel", "sofa"]`. They change no search; an entry that would merge them is refused unless the write says `despite_never`.
    
    - `words` (array of strings · required)

- `id` (string): The entry being changed, whose own words clash with nothing.

### Answers

- `200` (object): The words' counts and the clashes.
  
  - `channel` (string · required): A channel's id, such as `de` or `ch`: a market or storefront.
  
  - `locale` (string · required): The locale the words were searched in.
  
  - `entry` (object · required): The entry as it would be written: trimmed, lowercased and each word once.
    
    One entry of a language's synonyms.
    
    - `group` (kind: "group"): Words that mean the same, each way round, such as `["couch", "sofa"]`. A word or phrase is in one group at most.
      
      - `words` (array of strings · required)
    
    - `one_way` (kind: "one_way"): A word that also finds others, but not the other way round: `läufer` finds `teppich`. A word starts one such entry at most.
      
      - `from` (string · required)
      
      - `to` (array of strings · required)
    
    - `never` (kind: "never"): Words that look alike but must never be merged, such as `["sessel", "sofa"]`. They change no search; an entry that would merge them is refused unless the write says `despite_never`.
      
      - `words` (array of strings · required)
  
  - `words` (array of objects · required): Each word with what a shopper's search for it finds now, with the live synonyms, in the entry's order.
    
    A word and what searching for it finds.
    
    - `word` (string · required)
    
    - `total` (integer · required): How many results the search page lists for it.
  
  - `conflicts` (array of objects): Why writing it would be refused, as an add says; none when it can be written.
    
    A clash as data and as one sentence, such as "“sofa” is in the group couch, sofa, settee already."
    
    - `too_few` (id: "too_few"): It names fewer than two different words; a one-way entry names a word and at least one other it finds.
    
    - `taken` (id: "taken"): The word is in another group already, or starts another one-way entry: `entry` is the one to add to instead, with its words.
      
      - `word` (string · required)
      
      - `entry` (string · required): A synonym entry's place in `synonyms.json`: its language, its kind and its index there, such as `de/groups/0`, `de/one_way/2` or `de/never/0`. A delete moves the entries after it up, so a write names the draft version it read.
      
      - `words` (array of strings · required)
    
    - `never` (id: "never"): It merges two words the `never` entry `entry` keeps apart; for a `never` entry, `entry` is the one that merges them.
      
      - `words` (array of strings · required)
      
      - `entry` (string · required): A synonym entry's place in `synonyms.json`: its language, its kind and its index there, such as `de/groups/0`, `de/one_way/2` or `de/never/0`. A delete moves the entries after it up, so a write names the draft version it read.

- `400` ([problem](/docs/reference/problems#400)): The body names a channel or locale the release lacks.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

- `404` ([problem](/docs/reference/problems#404)): There is none.

- `422` ([problem](/docs/reference/problems#422)): The draft's synonyms.json cannot be read, or the entry has more than [`words_per_check`](/docs/reference/limits#words_per_check) words.

- `502` ([problem](/docs/reference/problems#502)): The Query API could not be reached.

- `503` ([problem](/docs/reference/problems#503)): Nothing is searchable yet, or the engine is unreachable.

## Show how each type is searched now: its fields, typo settings and exempt attributes

`GET /api/v1/search-settings`

How each type searches read is searched: its fields in priority order, where a word found in an earlier field ranks a hit higher, the fields it could search besides, whether and from how many letters on its words find with a typo, and the attributes exempt from typos, whose words are found only as written or by their start. Each setting says whether `types.json` sets it, the index run derived it from the catalog, or it is OrbSearch's default. Exempt attributes are derived from the catalog: the identifiers a type searches whose values nearly always belong to one product alone; `open` lists the identifiers left open to typos, each with why.

### Parameters

- `locale` (string): Default: the first channel's first locale.

### Answers

- `200` ([SearchSettings](#SearchSettings)): The search settings.

- `400` ([problem](/docs/reference/problems#400)): The locale is not one the release serves.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

- `502` ([problem](/docs/reference/problems#502)): The Query API could not be reached.

- `503` ([problem](/docs/reference/problems#503)): Nothing is searchable yet.

## Show how each type of a draft is searched

`GET /api/v1/imports/{import}/search-settings`

The same answer for the release a draft makes, with the draft's `version` to write on, its derived settings as the draft's run would derive them from the live catalog.

### Parameters

- `import` (string · required)

- `locale` (string): Default: the first channel's first locale.

### Answers

- `200` (object): The draft's search settings.
  
  - `version` (string · required): The draft's version this answer is of; the next write names it.
  
  - `settings` ([SearchSettings](#SearchSettings) · required): How every type of the release is searched.

- `400` ([problem](/docs/reference/problems#400)): The locale is not one the release serves.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

- `404` ([problem](/docs/reference/problems#404)): There is none.

- `422` ([problem](/docs/reference/problems#422)): The release the draft makes has violations; change it through the draft's files.

- `502` ([problem](/docs/reference/problems#502)): The Query API could not be reached.

- `503` ([problem](/docs/reference/problems#503)): Nothing is searchable yet.

## Change how one type of a draft is searched

`PATCH /api/v1/imports/{import}/search-settings/{type}`

Changes the type's searched fields, its typo settings or its exempt attributes, each named setting replaced whole; a setting left out stays, and `null` sets it back to its default, the import's or OrbSearch's. The Query API writes `types.json` and the draft checks the release as for `changeImport`. A draft without its own `types.json` starts from the types the live run derived. How it goes live, `showImportPublication` says: the order of the fields and the typo settings as settings within moments, the fields searched and the exempt attributes by a rebuild, since the engine reads every document again for them.

### Parameters

- `import` (string · required)

- `type` (string · required)

### Body

A change of how one type is searched and the draft version it is written on.

- `version` (string · required): The version of a draft: it changes with every change of the draft's release files, and with the release the draft builds on. A write names the version it read, and is refused when the draft has moved on. Treat it as opaque.

- `fields` (array of strings or null): The searched fields in priority order, all of them, at least one.

- `typos` (object or null): Whether and from how many letters on words find with a typo.
  
  - `enabled` (boolean · default: `true`): Off, a word finds only what holds it as written or starts with it. Default: on.
  
  - `one_typo` (integer · default: `5`): The fewest letters a word needs to find with one typo. Default: 5.
  
  - `two_typos` (integer · default: `9`): The fewest letters a word needs to find with two typos; at least `one_typo`. Default: 9.

- `exempt` (array of strings or null): The attributes exempt from typos, all of them; `[]` exempts none.

### Answers

- `200` (object): The draft's search settings after the write.
  
  - `version` (string · required): The draft's version this answer is of; the next write names it.
  
  - `settings` ([SearchSettings](#SearchSettings) · required): How every type of the release is searched.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

- `404` ([problem](/docs/reference/problems#404)): There is none.

- `409` ([problem](/docs/reference/problems#draftconflict)): The draft changed since `version` was read, and `draft` is the draft as it is now; or it was published or discarded, and `draft` is left out.

- `422` ([problem](/docs/reference/problems#422)): The write has violations, or the release it makes does; each names a JSON pointer and what is wrong. A change of fields to a rule they cannot express is refused here.

- `502` ([problem](/docs/reference/problems#502)): The Query API could not be reached.

## List the releases, newest first

`GET /api/v1/releases`

A page of releases, newest first, each marked as the live one, the previous one a rollback goes back to, or the one going live; `links` and `meta` lead to the others.

### Parameters

- `page` (integer · at least 1): The page, counted from 1. Default: 1.

- `per_page` (integer · 1 to 100): How many to a page. Default: 15.

### Answers

- `200` (object): The releases.
  
  - `data` ([array of StoredRelease](#StoredRelease) · required)
  
  - `links` ([PageLinks](#PageLinks) · required): The pages around this one, as URLs to fetch.
  
  - `meta` ([PageMeta](#PageMeta) · required): Where this page stands in the whole list.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

```sh title="Terminal"
curl -s -H "Authorization: Bearer $key" $api/releases | jq '{data: [.data[] | {id, role, course}], meta}'
```

```json title="Answer: 200 · 18 ms"
{
  "data": [
    {
      "id": "b25a6aaac6a46319b4ee3d25",
      "role": "live",
      "course": {
        "way": "rebuild",
        "because": {
          "id": "nothing_live"
        },
        "sentence": "Builds the search: nothing is live yet."
      }
    }
  ],
  "meta": {
    "current_page": 1,
    "last_page": 1,
    "per_page": 15,
    "total": 1
  }
}
```

## Store a release

`POST /api/v1/releases`

Each file as its JSON object, or as text. The Query API checks the release and writes its files canonically; the same content is the same release. Storing does not publish.

### Body

A release to store: its files by name, each as its JSON object or as text, such as `{ "files": { "channels.json": { "channels": [...] } } }`.

- `files` (object · required)

### Answers

- `200` ([StoredRelease](#StoredRelease)): The same release was stored before.

- `201` ([StoredRelease](#StoredRelease)): The release is stored.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

- `422` ([problem](/docs/reference/problems#422)): The release has violations.

- `502` ([problem](/docs/reference/problems#502)): The Query API could not check it.

## Show a release with its files

`GET /api/v1/releases/{release}`

Its files are the canonical text the Query API wrote, so the panel and Git hold the same bytes.

### Parameters

- `release` (string · required)

### Answers

- `200` ([StoredRelease](#StoredRelease)): The release.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

- `404` ([problem](/docs/reference/problems#404)): There is none.

## Publish a release, or roll back to an earlier one

`POST /api/v1/releases/{release}/publish`

An index run takes it live with the current catalog, the one uploaded last that the indexer did not reject, the way `showReleasePublication` says: switched in at once, after settings, or by a rebuild. Searches read it once the run goes live, and the run's report says how it went. Publishing an earlier release again is a rollback.

### Parameters

- `release` (string · required)

### Answers

- `202` (object): The release is published.
  
  - `release` ([StoredRelease](#StoredRelease) · required): A release as the control plane stores it, with when it was published. Storing does not publish it.
  
  - `run` ([IndexRun](#IndexRun)): The index run that makes it live; none before a catalog is uploaded.
  
  - `next` (string · required): What happens next, as a sentence.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

- `404` ([problem](/docs/reference/problems#404)): There is none.

## Show how publishing the release would go live, before it does

`GET /api/v1/releases/{release}/publication`

What publishing the release would do with the catalog an index run would use now, decided by the decision the indexer takes: `course` says whether it goes live at once (a switch), after settings the engine applies without reindexing, or by a rebuild of the indexes, and why, as data and as a sentence. For a rebuild, `estimate_seconds` is about how long it takes, from the last rebuild; the shop keeps answering with the live release meanwhile. Publishing an earlier release again, a rollback, is decided the same way. Nothing is published.

### Parameters

- `release` (string · required)

### Answers

- `200` (object): How publishing would go live.
  
  - `course` ([Course](#Course) · required): The way a release goes live and why, as data and as a sentence.
  
  - `estimate_seconds` (integer): For a rebuild: about how many seconds it takes, from the time of the last rebuild. It grows with the catalog, so a much larger catalog takes longer. Left out for any other way, and before a first rebuild.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

- `404` ([problem](/docs/reference/problems#404)): There is none.

- `409` ([problem](/docs/reference/problems#409)): There is no catalog yet, so nothing can be indexed before one is uploaded.

- `422` ([problem](/docs/reference/problems#422)): The draft files make a release with violations; each names its file, a JSON pointer and what is wrong.

- `502` ([problem](/docs/reference/problems#502)): The Query API could not be reached.

## List the index runs, newest first

`GET /api/v1/index-runs`

A page of index runs, newest first; `links` and `meta` lead to the others.

### Parameters

- `page` (integer · at least 1): The page, counted from 1. Default: 1.

- `per_page` (integer · 1 to 100): How many to a page. Default: 15.

### Answers

- `200` (object): The index runs.
  
  - `data` ([array of IndexRun](#IndexRun) · required)
  
  - `links` ([PageLinks](#PageLinks) · required): The pages around this one, as URLs to fetch.
  
  - `meta` ([PageMeta](#PageMeta) · required): Where this page stands in the whole list.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

## Index the current catalog with the published release again

`POST /api/v1/index-runs`

What brings search back after the engine lost its indexes.

### Answers

- `202` ([IndexRun](#IndexRun)): The run is queued.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

- `409` ([problem](/docs/reference/problems#409)): There is no catalog or no published release yet.

## Show an index run with its report

`GET /api/v1/index-runs/{index_run}`

The report names every row of the feed the run left out, with its field and why.

### Parameters

- `index_run` (string · required)

### Answers

- `200` ([IndexRun](#IndexRun)): The index run.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

- `404` ([problem](/docs/reference/problems#404)): There is none.

## Show what searches read now

`GET /api/v1/live`

The index run searches read, with its release and snapshot, and in its report the offer changes it applied with the time the latest arrived; 404 before any run went live.

### Answers

- `200` ([IndexRun](#IndexRun)): The index run.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

- `404` ([problem](/docs/reference/problems#404)): There is none.

```sh title="Terminal"
curl -s -H "Authorization: Bearer $key" $api/live | jq '{id, state, release_id, snapshot_id, live}'
```

```json title="Answer: 200 · 11 ms"
{
  "id": 1,
  "state": "succeeded",
  "release_id": "b25a6aaac6a46319b4ee3d25",
  "snapshot_id": "753be49b9a9a503b3affac97",
  "live": true
}
```

## Change prices and stock without sending the catalog

`PUT /api/v1/offers`

A batch of offer changes, each a product's price, sale, stock, availability or delivery days in one channel; the fields a change leaves out stay as they are. Each change is answered on its own: kept, or left out with a code and a sentence, such as for a product the live catalog lacks. The changes kept make one revision. Within seconds, the indexer compiles the changed products again and replaces their documents in the live indexes; batches sent close together are written together, and no index run is queued. Once searches read them, `GET /api/v1/live` and every trace name the revision. The same catalog sent again keeps the changes, another catalog supersedes them, and a rebuild never undoes a change that came after its catalog. Until the next run, what the run derived from the whole catalog stays as it was: the dictionary's counts, derived price buckets and the values each facet counts. A product an overlay hides because of its new offer leaves search at once, and a sale window that opens or closes builds the search again at that moment.

### Body

A batch of offer changes, such as `{ "offers": [{ "product": "SOFA-MALMO", "variant": "SOFA-MALMO-GREY", "channel": "de", "price": 899, "availability": "in_stock" }] }`, each answered on its own.

- `offers` (array of objects · required): At most [`offers_per_call`](/docs/reference/limits#offers_per_call).
  
  A change of one product's offer in one channel. The fields given replace the offer's, the fields left out stay as they are. A product without variants is changed as itself; a product with variants names the variant. A channel the product has no offer in yet gets one.
  
  - `product` (string · required): The product's id in the catalog.
  
  - `variant` (string): The merchant's id of an entity, unique per type, such as `SOFA-LUND-3`. It travels unchanged; OrbSearch never rewrites it.
  
  - `channel` (string · required): A channel's id, such as `de` or `ch`: a market or storefront.
  
  - `price` (number): In the channel's currency, in its major unit.
  
  - `sale_price` (number): The reduced price, valid within `sale_window` if one is given.
  
  - `sale_window` (object): A window in time: from `from` (inclusive) until `until` (exclusive). Either end may be open.
    
    - `from` (string): A point in time as RFC 3339 with an offset, such as `2026-11-27T00:00:00+01:00`.
    
    - `until` (string): A point in time as RFC 3339 with an offset, such as `2026-11-27T00:00:00+01:00`.
  
  - `end_sale` (boolean): Ends the sale: the sale price and its window go, and the price holds.
  
  - `availability` (string): One of `in_stock`, `out_of_stock`, `preorder` or `backorder`.
  
  - `stock` (integer)
  
  - `delivery_days` (object): How many days delivery takes, from the earliest to the latest.
    
    - `min` (integer · required)
    
    - `max` (integer · required)

### Answers

- `202` (object): Each change is answered.
  
  - `revision` (integer): The revision the kept changes make; left out when none was kept.
  
  - `rows` (array of objects · required): One verdict per change, in the order sent.
    
    What became of one change.
    
    - `accepted` (state: "accepted"): Kept; it reaches search with the revision.
    
    - `rejected` (state: "rejected"): Left out, and why; the other changes of the batch are kept.
      
      - `code` (string · required): Why a change was left out. Codes are stable; the sentence beside them may change.
        
        - `unreadable`: The change is not an object of the fields above, such as a price written as text.
        
        - `unknown_product`: The live catalog has no product with this id; a new product arrives with the catalog.
        
        - `unknown_variant`: The product has no variant with this id, or no variants at all.
        
        - `variant_needed`: The product has variants, so the change names the one it changes.
        
        - `unknown_channel`: The channel is not one of the live release.
        
        - `invalid_value`: A value no offer can hold, such as a negative price, a sale window that ends before it starts, delivery days whose `min` is above their `max`, or a sale price beside `end_sale`.
        
        - `nothing_changed`: The change names no field to change.
      
      - `message` (string · required)
  
  - `next` (string · required): What happens next, as a sentence.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

- `409` ([problem](/docs/reference/problems#409)): Nothing is live yet, so no product is known; send a catalog first.

- `422` ([problem](/docs/reference/problems#422)): The body holds no list of offers, or more than [`offers_per_call`](/docs/reference/limits#offers_per_call).

- `502` ([problem](/docs/reference/problems#502)): The Query API could not check them.

## Show what the storage keeps and the disk it takes

`GET /api/v1/storage`

The indexer cleans up once it starts and after every run that goes live. It keeps the snapshot of the live run, of every run still queued or running, of every draft and of an import that failed since the live run went live, the current catalog, and the newest `kept_snapshots` others that went live. Every other file goes; its row stays with `removed_at`, and so do its runs. It also drops the dictionaries of runs that are not live and the engine indexes no run uses, then measures the engine.

### Answers

- `200` (object): The storage.
  
  - `kept_snapshots` (integer · required): How many snapshots that went live are kept beside the live one, newest first. Default: 5.
  
  - `snapshots` (object · required): The snapshot files in the storage.
    
    Files and the bytes they take together.
    
    - `count` (integer · required)
    
    - `bytes` (integer · required)
  
  - `engine` (object): The engine's indexes on disk, as the indexer measured them after it last cleaned up; left out before it did.
    
    The engine's size on disk, when it was measured.
    
    - `bytes` (integer · required)
    
    - `measured_at` (string · required): A point in time as RFC 3339 with an offset, such as `2026-11-27T00:00:00+01:00`.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

## Change how many earlier catalogs are kept

`PATCH /api/v1/storage`

Takes effect at the indexer's next clean-up, after the next run that goes live or when it starts. Keeping fewer removes files; keeping more brings none back.

### Body

A change of what the storage keeps.

- `kept_snapshots` (integer · at most 100 · required): How many snapshots that went live to keep beside the live one, newest first.

### Answers

- `200` (object): The storage, with the new setting.
  
  - `kept_snapshots` (integer · required): How many snapshots that went live are kept beside the live one, newest first. Default: 5.
  
  - `snapshots` (object · required): The snapshot files in the storage.
    
    Files and the bytes they take together.
    
    - `count` (integer · required)
    
    - `bytes` (integer · required)
  
  - `engine` (object): The engine's indexes on disk, as the indexer measured them after it last cleaned up; left out before it did.
    
    The engine's size on disk, when it was measured.
    
    - `bytes` (integer · required)
    
    - `measured_at` (string · required): A point in time as RFC 3339 with an offset, such as `2026-11-27T00:00:00+01:00`.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

- `422` ([problem](/docs/reference/problems#422)): The setting is out of range.

## Show what shoppers searched and clicked, what found nothing and the filters they chose

`GET /api/v1/insights`

From the search log's daily rollups, for UTC days `from` to `to`: the searches, those that found nothing, those with a click and those with results but no click, each with its denominator, per day too with the Query API's latency, where clicked hits stood, the queries searched most, those that found nothing and those that drew no click most often, the filters chosen per page, and the releases that answered. The Query API logs what it answers on `/v1/search` and on `/v1/resolve` with results, never a preview, and the clicks and views storefronts send to `/v1/events`; the control plane rolls the log up about once a minute and joins each click to its search by query ID for [`event_hours`](/docs/reference/limits#event_hours), so a search or a click shows within a minute or two, and late or unmatched events are counted. One kind of traffic is counted, shoppers by default; `left_out` says how many answers to tests, benchmarks and bots that left out, and how many searches each rule kept out of the queries: a query reaches them once two page views typed it that day, never with an email address or a phone number in it. Raw searches are kept 60 days; the rollups stay.

### Parameters

- `from` (string): The first UTC day counted. Default: 29 days before `to`.

- `to` (string): The last UTC day counted. Default: today.

- `traffic` (string): The kind of traffic counted. Default: `shopper`.
  
  - `shopper`: Everyone a storefront serves that none of the below is.
  
  - `test`: End-to-end tests, which mark their requests so.
  
  - `bench`: A latency benchmark, which marks its requests so.
  
  - `bot`: A crawler or another bot, as uap-core's maintained user agent rules name it; the Query API decides this from the `User-Agent` header of a request that says it is a shopper's.

- `limit` (integer · 1 to 100): Rows in each list. Default: 20.

### Answers

- `200` (object): The report.
  
  - `from` (string · required): A UTC day, such as `2026-10-09`.
  
  - `to` (string · required): A UTC day, such as `2026-10-09`.
  
  - `traffic` (string · required): Whose searches these are. A report counts one kind and says how many answers to the others it left out.
    
    - `shopper`: Everyone a storefront serves that none of the below is.
    
    - `test`: End-to-end tests, which mark their requests so.
    
    - `bench`: A latency benchmark, which marks its requests so.
    
    - `bot`: A crawler or another bot, as uap-core's maintained user agent rules name it; the Query API decides this from the `User-Agent` header of a request that says it is a shopper's.
  
  - `rolled_up_at` (string): When the log was last rolled up, about once a minute; a search shows at the next roll-up. Left out until the first.
  
  - `releases` (array of strings · required): The releases that answered the searches counted, the latest first.
  
  - `searches` (integer · required)
  
  - `no_results` (object · required): The searches that found nothing: no section held a result and nothing redirected.
    
    A count and what it is a share of, such as 12 searches that found nothing of 140.
    
    - `count` (integer · required)
    
    - `of` (integer · required)
  
  - `click_through` (object · required): The searches with a click, of all searches.
    
    A count and what it is a share of, such as 12 searches that found nothing of 140.
    
    - `count` (integer · required)
    
    - `of` (integer · required)
  
  - `no_click` (object · required): The searches with results and no click, of the searches with results.
    
    A count and what it is a share of, such as 12 searches that found nothing of 140.
    
    - `count` (integer · required)
    
    - `of` (integer · required)
  
  - `average_position` (number): Where the clicked hits of the listed section stood, on average, counted from 1 across the pages; left out without such a click.
  
  - `category_pages` (integer · required): First pages of category listings.
  
  - `autocomplete` (integer · required): Answers to a search box while the shopper typed.
  
  - `distinct_queries` (integer · required): The queries counted in `queries`, over every day.
  
  - `days` (array of objects · required): Every day of the range, one without searches included.
    
    - `day` (string · required): A UTC day, such as `2026-10-09`.
    
    - `searches` (integer · required)
    
    - `no_results` (integer · required): Of `searches`.
    
    - `clicked` (integer · required): Of `searches`, those with a click.
    
    - `category_pages` (integer · required)
    
    - `autocomplete` (integer · required)
    
    - `took_ms` (object): How long the Query API took for the day's answers on the search page, the pages after the first included; left out on a day without any.
      
      - `p50` (number · required)
      
      - `p95` (number · required)
      
      - `p99` (number · required)
  
  - `queries` ([array of QueryInsight](#QueryInsight) · required): The queries searched most, by their words as the engine reads them. A query is counted on a day once two page views typed it that day.
  
  - `no_result_queries` ([array of QueryInsight](#QueryInsight) · required): The queries that found nothing most often, the same way counted.
  
  - `no_click_queries` ([array of QueryInsight](#QueryInsight) · required): The queries whose searches had results and drew no click most often, the same way counted.
  
  - `pages` (array of objects · required): The pages searched most, the search page among them, each with the filters chosen on it.
    
    - `category` (string): The category page's category; left out for the search page.
    
    - `searches` (integer · required): First pages of its results.
    
    - `filtered` (integer · required): Of `searches`, those with a filter chosen.
    
    - `filters` (array of objects · required): The filters chosen, the most chosen first: each with the searches that chose it, of `searches`.
      
      - `field` (string · required): The facet's field, or `category` for the category facet.
      
      - `searches` (integer · required)
  
  - `left_out` (object · required): How many each rule of the log left out of this report.
    
    - `traffic` (map of integers · required): The first pages answered to every other kind of traffic, on every surface.
    
    - `rare_queries` (integer · required): Searches whose query fewer than two page views typed that day, or that is longer than 200 characters: counted in `searches`, never shown as a query.
    
    - `personal_data` (integer · required): Searches whose query held an email address or a phone number, which the log masked: counted in `searches`, never shown as a query.
    
    - `not_recorded` (integer · required): Searches of any traffic the Query API answered but could not log, since its buffer was full or Postgres did not take them.
    
    - `events` (object · required): The clicks and views no search of the report counts.
      
      - `late` (integer · required): Events of any traffic that arrived on one of the days more than [`event_hours`](/docs/reference/limits#event_hours) after their answer, which the Query API refused.
      
      - `unmatched` (integer · required): Events of this traffic for an answer on one of the days that the log holds nothing of this traffic for: a preview's, one the log could not record, another traffic's, or a made-up query ID.
      
      - `not_recorded` (integer · required): Events of any traffic the Query API took on one of the days but could not log, since its buffer was full or Postgres did not take them.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

- `422` ([problem](/docs/reference/problems#422)): A day or the traffic is not one the report can count.

## Show the views and clicks of each sponsored products' campaign

`GET /api/v1/insights/campaigns`

From the daily rollups, for UTC days `from` to `to`: per campaign of the sponsored pins, the answers that served its products, the views of them and the share clicked, per day too. A view counts once per query ID and product, once a storefront reported half of the tile visible for a second or a click on it; an event counts only where an answer of its page, of its traffic, placed the product with the campaign it names, and for that answer's day, within [`event_hours`](/docs/reference/limits#event_hours). One kind of traffic is counted, shoppers by default. With `Accept: text/csv` the same report comes as a CSV to send to the brand, one row per campaign. The rollups outlive the 60 days of raw searches and events, so a campaign's report reaches back as far as the shop has run it.

### Parameters

- `from` (string): The first UTC day counted. Default: 29 days before `to`.

- `to` (string): The last UTC day counted. Default: today.

- `traffic` (string): The kind of traffic counted. Default: `shopper`.
  
  - `shopper`: Everyone a storefront serves that none of the below is.
  
  - `test`: End-to-end tests, which mark their requests so.
  
  - `bench`: A latency benchmark, which marks its requests so.
  
  - `bot`: A crawler or another bot, as uap-core's maintained user agent rules name it; the Query API decides this from the `User-Agent` header of a request that says it is a shopper's.

### Answers

- `200` (object): The report.
  
  - `from` (string · required): A UTC day, such as `2026-10-09`.
  
  - `to` (string · required): A UTC day, such as `2026-10-09`.
  
  - `traffic` (string · required): Whose searches these are. A report counts one kind and says how many answers to the others it left out.
    
    - `shopper`: Everyone a storefront serves that none of the below is.
    
    - `test`: End-to-end tests, which mark their requests so.
    
    - `bench`: A latency benchmark, which marks its requests so.
    
    - `bot`: A crawler or another bot, as uap-core's maintained user agent rules name it; the Query API decides this from the `User-Agent` header of a request that says it is a shopper's.
  
  - `rolled_up_at` (string): When the log was last rolled up, about once a minute. Left out until the first.
  
  - `campaigns` (array of objects · required): Every campaign served or seen in the range, the most viewed first.
    
    - `campaign` (string · required): A sponsored placement's campaign, the merchant's name for it, such as `Michelin spring`: one line of up to 200 characters, which reports and their CSV group views and clicks by.
    
    - `served` (integer · required): The answers that placed one of its products, every page counted.
    
    - `views` (integer · required): Its products seen: each once per query ID, once half of its tile was visible for a second or it was clicked.
    
    - `click_through` (object · required): The views clicked, of `views`.
      
      A count and what it is a share of, such as 12 searches that found nothing of 140.
      
      - `count` (integer · required)
      
      - `of` (integer · required)
    
    - `days` (array of objects · required): The days of the range it was served or seen on, the earliest first.
      
      - `day` (string · required): A UTC day, such as `2026-10-09`.
      
      - `served` (integer · required)
      
      - `views` (integer · required)
      
      - `clicks` (integer · required): Of `views`, those clicked.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

- `422` ([problem](/docs/reference/problems#422)): A day or the traffic is not one the report can count.

## Show the category tree of what is live

`GET /api/v1/categories`

Every category of the live catalog with its parent, titles, paths and channels, and the type its page lists with how many entities that is, named by the release and the catalog snapshot that answered. The nodes name their parents, so the caller arranges the tree.

### Answers

- `200` (object): The categories.
  
  - `release` (string · required): The configuration that is live.
  
  - `snapshot` (string · required): The catalog the categories are read from.
  
  - `categories` (array of objects · required): Every category, by id. Each names its parent, so a client arranges the tree itself; a parent does not necessarily come before its children.
    
    One category node of the live catalog.
    
    - `id` (string · required): The id of a category node, such as `wohnen/sofas`: the merchant's id of a `category` entity.
    
    - `parent` (string): The parent node; left out for a root.
    
    - `title` (string or map of strings): What the node is called per locale; left out where the catalog gives no title.
    
    - `path` (string or map of strings): The page's path in the merchant's shop per locale, such as `/wohnen/sofas`; left out where the catalog gives none.
    
    - `channels` (array of strings): The channels the node exists in; left out where it exists in every channel.
    
    - `lists` (string · required): The type its page lists: the type with offers most of the entities in it or below it are, `product` where it holds nothing.
    
    - `listed` (integer · required): How many entities of that type sit in it or below it.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

- `502` ([problem](/docs/reference/problems#502)): The Query API could not be reached.

- `503` ([problem](/docs/reference/problems#503)): Nothing is searchable yet.

```sh title="Terminal"
curl -s -H "Authorization: Bearer $key" $api/categories | jq '.categories[:2]'
```

```json title="Answer: 200 · 7.6 ms · release b25a6aaa"
[
  {
    "id": "leuchten",
    "title": {
      "de": "Leuchten",
      "en": "Lighting"
    },
    "path": {
      "de": "/leuchten",
      "en": "/en/lighting"
    },
    "lists": "product",
    "listed": 3
  },
  {
    "id": "leuchten/stehleuchten",
    "parent": "leuchten",
    "title": {
      "de": "Stehleuchten",
      "en": "Floor lamps"
    },
    "path": {
      "de": "/leuchten/stehleuchten",
      "en": "/en/lighting/floor-lamps"
    },
    "lists": "product",
    "listed": 2
  }
]
```

## Show what a page shows and where each setting comes from

`POST /api/v1/pages/settings`

A category page, or the search page without `category`, as a search on it reads it: its facets in display order with their groups, the order it starts in and the orders it offers, and every order a page can offer. Each setting names where it comes from: the page itself, the nearest category above it that sets it (`Sort: price, from Wohnen`), the default layout, or nothing; and whether the merchant wrote it or the index run derived it from the catalog, with the run's reason. Labels are in the locale, and `url` is the page's address. With `files`, such as a draft's `categories.json`, the settings are read from them over the live release, so a draft's page is seen before it is published; what the live index run derived stays as it derived it until then.

### Body

The page whose settings to show.

- `category` (string): The category whose page it is, such as `wohnen/sofas`. Default: the search page.

- `channel` (string): The channel. Default: the release's first channel.

- `locale` (string): The locale the labels and the address are in. Default: the channel's first locale.

- `files` (map of strings): Release files by name in place of the live release's own, such as a draft's `categories.json`: the settings are read from them, completed with what the live index run derived, so a draft's page is seen before it is published. What the run derived stays as it derived it until the draft is published, also where the draft changes what it was derived from, such as the default facets the categories follow.

### Answers

- `200` (object): The page's settings.
  
  - `release` (string · required): The configuration that decided: the live release, or the draft the files make.
  
  - `snapshot` (string · required): The catalog the categories are read from.
  
  - `channel` (string · required): A channel's id, such as `de` or `ch`: a market or storefront.
  
  - `locale` (string · required): A BCP 47 language tag such as `de`, `de-CH` or `en`. A locale falls back along its tag: `de-CH` to `de`.
  
  - `category` (string): The category whose page it is; left out for the search page.
  
  - `title` (string): The category's title in the locale; left out for the search page.
  
  - `url` (string): Where the shop shows the page in the locale: the category's path, or the search page's. Left out where the category has no page in the channel.
  
  - `facets` (object · required): The facets a page shows, in display order, a group's facets together.
    
    - `origin` (object · required): The list is taken whole from one place.
      
      Where a setting of a page comes from. A page takes each setting from the nearest category up the tree that sets it, else from the default layout of `categories.json`.
      
      - `page` (from: "page"): The page's own category sets it.
        
        - `derived` (boolean): The release leaves it out, so the index run derived it from the catalog.
      
      - `category` (from: "category"): The nearest category above the page that sets it, which the page inherits it from.
        
        - `category` (string · required): The id of a category node, such as `wohnen/sofas`: the merchant's id of a `category` entity.
        
        - `title` (string · required): The category's title in the locale, or its id where the catalog gives none.
        
        - `derived` (boolean): The release leaves it out, so the index run derived it from the catalog.
      
      - `default` (from: "default"): The default layout, which every page that sets none inherits.
        
        - `derived` (boolean): The release leaves it out, so the index run derived it from the catalog.
      
      - `built_in` (from: "built_in"): Nothing sets it, so the page has none, or starts by relevance.
    
    - `facets` (array of objects · required): One facet of a page.
      
      - `field` (string · required): A field a selector, filter or facet reads: an attribute code, or one of the built-in fields `category`, `brand`, `price`, `on_sale`, `availability`, `delivery_days` and `rating`.
      
      - `label` (string · required): The field's name in the locale.
      
      - `kind` (string · required): How the facet is shown, its natural kind where the layout names none.
        
        - `list`
        
        - `swatch`
        
        - `hierarchical`
        
        - `range`
        
        - `buckets`
        
        - `toggle`
        
        - `relative`: Dates relative to the request's time, such as "new in the last 30 days". Bucket bounds are days.
      
      - `shown` ([ShownFacet](#ShownFacet) · required): How the list writes it, or for a field code alone, how the default layout shows the field.
      
      - `shown_as_default` (boolean): The list names the field alone, so `shown` is how the default layout shows it.
      
      - `group` (object): The group the page draws it in.
        
        The group a facet stands in, as every facet of it says.
        
        - `group` (string · required): The code of a group of facets on a page, such as `tyre_size`.
        
        - `label` (string · required): The heading, in the request's locale.
        
        - `display` (string): How a group of facets is drawn.
          
          - `finder`: One select beside the next, each with "Any" first and every value counted under the choices of the others, such as a tyre's width, ratio and rim. Each of its facets is shown as `select`.
      
      - `reason` (object): Why the index run chose it, where the list is derived.
        
        What in the catalog decided a derived setting. Codes are stable, so the panel translates them.
        
        - `entities` (by: "entities"): The catalog holds entities of this built-in type, or the export makes them, such as categories from paths.
          
          - `count` (integer · required)
        
        - `language` (by: "language"): Most words that tell languages apart are this language's, in this share of them, in percent.
          
          - `locale` (string · required): A BCP 47 language tag such as `de`, `de-CH` or `en`. A locale falls back along its tag: `de-CH` to `de`.
          
          - `share` (integer · required)
        
        - `keyed` (by: "keyed"): Texts are keyed by this locale in this many entities.
          
          - `locale` (string · required): A BCP 47 language tag such as `de`, `de-CH` or `en`. A locale falls back along its tag: `de-CH` to `de`.
          
          - `entities` (integer · required)
        
        - `currency` (by: "currency"): Prices name this currency, written as in `written`, in this many values.
          
          - `currency` (string · required): An ISO 4217 currency code, such as `EUR`.
          
          - `written` (string · required)
          
          - `count` (integer · required)
        
        - `language_currency` (by: "language_currency"): No price names a currency, so the one the language usually pays in is taken.
          
          - `currency` (string · required): An ISO 4217 currency code, such as `EUR`.
          
          - `locale` (string · required): A BCP 47 language tag such as `de`, `de-CH` or `en`. A locale falls back along its tag: `de-CH` to `de`.
        
        - `values` (by: "values"): This share of the values, in percent, reads as this type; a quantity also names the unit most of them use.
          
          - `type` (string · required): - `boolean`
            
            - `text`: Free text: searchable, never a filter.
            
            - `identifier`: GTIN, MPN, ISBN and similar: exact match after normalization.
            
            - `option`: Enumerated values with labels, aliases, order, groups and swatches.
            
            - `number`: A number without a unit.
            
            - `quantity`: A number with a unit of one dimension.
            
            - `range`: A minimum and a maximum with a unit, such as age 3 to 6.
            
            - `date`: A date or a point in time.
          
          - `unit` (string): A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `mm`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `cm`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `m`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `in`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `ft`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `g`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `kg`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `lb`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `oz`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `ml`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `l`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `w`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `kw`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `wh`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `kwh`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `mah`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `v`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `lm`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `kelvin`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `celsius`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `hz`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `mb`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `gb`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `tb`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `day`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `month`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `year`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
          
          - `share` (integer · required)
          
          - `values` (integer · required): Values read, and how many of them differ, up to a cap.
          
          - `distinct` (integer · required)
        
        - `varies` (by: "varies"): The variants carry the value in this many products, so it is the variants': an export puts there what differs inside a group, JSON Lines what the merchant wrote on the variants.
          
          - `products` (integer · required)
        
        - `lists` (by: "lists"): This many values arrive as lists, which only an attribute that takes several values reads.
          
          - `count` (integer · required)
        
        - `colors` (by: "colors"): This share of the values, in percent, are color words, so the import places them in color groups.
          
          - `share` (integer · required)
        
        - `codes` (by: "codes"): This share of the values, in percent, are machine codes such as `HOME_FURNITURE_AND_DECOR`: data for rules, not words a shopper filters by, so the attribute is no filter.
          
          - `share` (integer · required)
        
        - `faceted` (by: "faceted"): The search pages filter by this option, so a query that names one of its values or groups is read as that filter (`detect_in_query`), within the token dimensions its facet already spends.
        
        - `carried` (by: "carried"): A facet: this many of the page's products carry the field, with this many different values.
          
          - `products` (integer · required)
          
          - `of` (integer · required)
          
          - `values` (integer · required)
        
        - `always` (by: "always"): Every shop offers it: relevance and price sorting, the price and category facets.
        
        - `offers` (by: "offers"): Offers carry what it reads, such as delivery days or sale prices, in this many items.
          
          - `count` (integer · required)
        
        - `signal` (by: "signal"): The catalog carries this signal in this many entities.
          
          - `signal` (string · required): The code of a signal, such as `sales_30d` or `rating`.
          
          - `entities` (integer · required)
        
        - `unique` (by: "unique"): This share of an identifier's values, in percent, of this many, belong to one product alone: a typo in one names another product, so the attribute is exempt from typos.
          
          - `share` (integer · required)
          
          - `values` (integer · required)
        
        - `shared` (by: "shared"): Only this share of an identifier's values, in percent, of this many, belong to one product alone: products share them, as cross-reference numbers are, so typos still find them.
          
          - `share` (integer · required)
          
          - `values` (integer · required)
        
        - `few` (by: "few"): Too few of an identifier's values, this many, tell whether they belong to one product each, so typos still find them.
          
          - `values` (integer · required)
  
  - `groups` (object · required): The groups of facets a page draws under one heading.
    
    - `origin` (object · required): Where a setting of a page comes from. A page takes each setting from the nearest category up the tree that sets it, else from the default layout of `categories.json`.
      
      - `page` (from: "page"): The page's own category sets it.
        
        - `derived` (boolean): The release leaves it out, so the index run derived it from the catalog.
      
      - `category` (from: "category"): The nearest category above the page that sets it, which the page inherits it from.
        
        - `category` (string · required): The id of a category node, such as `wohnen/sofas`: the merchant's id of a `category` entity.
        
        - `title` (string · required): The category's title in the locale, or its id where the catalog gives none.
        
        - `derived` (boolean): The release leaves it out, so the index run derived it from the catalog.
      
      - `default` (from: "default"): The default layout, which every page that sets none inherits.
        
        - `derived` (boolean): The release leaves it out, so the index run derived it from the catalog.
      
      - `built_in` (from: "built_in"): Nothing sets it, so the page has none, or starts by relevance.
    
    - `groups` (array of objects · required): Every group the page's layout sets; one whose page lists fewer than two of its facets is drawn apart.
      
      A group of facets as the layout sets it.
      
      - `group` (string · required): The code of a group of facets on a page, such as `tyre_size`.
      
      - `label` (string · required): The heading, in the locale.
      
      - `facets` (array of strings · required)
      
      - `display` (string): How a group of facets is drawn.
        
        - `finder`: One select beside the next, each with "Any" first and every value counted under the choices of the others, such as a tyre's width, ratio and rim. Each of its facets is shown as `select`.
  
  - `sort` (object · required): The order a page starts in and the orders it offers.
    
    - `default` (object · required): The order the page starts in while the shopper chooses none and types no words.
      
      The order a page starts in.
      
      - `sort` ([SortOption](#SortOption) · required): An order a page offers.
      
      - `origin` (object · required): Where a setting of a page comes from. A page takes each setting from the nearest category up the tree that sets it, else from the default layout of `categories.json`.
        
        - `page` (from: "page"): The page's own category sets it.
          
          - `derived` (boolean): The release leaves it out, so the index run derived it from the catalog.
        
        - `category` (from: "category"): The nearest category above the page that sets it, which the page inherits it from.
          
          - `category` (string · required): The id of a category node, such as `wohnen/sofas`: the merchant's id of a `category` entity.
          
          - `title` (string · required): The category's title in the locale, or its id where the catalog gives none.
          
          - `derived` (boolean): The release leaves it out, so the index run derived it from the catalog.
        
        - `default` (from: "default"): The default layout, which every page that sets none inherits.
          
          - `derived` (boolean): The release leaves it out, so the index run derived it from the catalog.
        
        - `built_in` (from: "built_in"): Nothing sets it, so the page has none, or starts by relevance.
      
      - `reason` (object): Why the index run chose it, where it is derived.
        
        What in the catalog decided a derived setting. Codes are stable, so the panel translates them.
        
        - `entities` (by: "entities"): The catalog holds entities of this built-in type, or the export makes them, such as categories from paths.
          
          - `count` (integer · required)
        
        - `language` (by: "language"): Most words that tell languages apart are this language's, in this share of them, in percent.
          
          - `locale` (string · required): A BCP 47 language tag such as `de`, `de-CH` or `en`. A locale falls back along its tag: `de-CH` to `de`.
          
          - `share` (integer · required)
        
        - `keyed` (by: "keyed"): Texts are keyed by this locale in this many entities.
          
          - `locale` (string · required): A BCP 47 language tag such as `de`, `de-CH` or `en`. A locale falls back along its tag: `de-CH` to `de`.
          
          - `entities` (integer · required)
        
        - `currency` (by: "currency"): Prices name this currency, written as in `written`, in this many values.
          
          - `currency` (string · required): An ISO 4217 currency code, such as `EUR`.
          
          - `written` (string · required)
          
          - `count` (integer · required)
        
        - `language_currency` (by: "language_currency"): No price names a currency, so the one the language usually pays in is taken.
          
          - `currency` (string · required): An ISO 4217 currency code, such as `EUR`.
          
          - `locale` (string · required): A BCP 47 language tag such as `de`, `de-CH` or `en`. A locale falls back along its tag: `de-CH` to `de`.
        
        - `values` (by: "values"): This share of the values, in percent, reads as this type; a quantity also names the unit most of them use.
          
          - `type` (string · required): - `boolean`
            
            - `text`: Free text: searchable, never a filter.
            
            - `identifier`: GTIN, MPN, ISBN and similar: exact match after normalization.
            
            - `option`: Enumerated values with labels, aliases, order, groups and swatches.
            
            - `number`: A number without a unit.
            
            - `quantity`: A number with a unit of one dimension.
            
            - `range`: A minimum and a maximum with a unit, such as age 3 to 6.
            
            - `date`: A date or a point in time.
          
          - `unit` (string): A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `mm`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `cm`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `m`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `in`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `ft`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `g`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `kg`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `lb`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `oz`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `ml`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `l`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `w`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `kw`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `wh`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `kwh`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `mah`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `v`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `lm`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `kelvin`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `celsius`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `hz`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `mb`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `gb`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `tb`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `day`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `month`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `year`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
          
          - `share` (integer · required)
          
          - `values` (integer · required): Values read, and how many of them differ, up to a cap.
          
          - `distinct` (integer · required)
        
        - `varies` (by: "varies"): The variants carry the value in this many products, so it is the variants': an export puts there what differs inside a group, JSON Lines what the merchant wrote on the variants.
          
          - `products` (integer · required)
        
        - `lists` (by: "lists"): This many values arrive as lists, which only an attribute that takes several values reads.
          
          - `count` (integer · required)
        
        - `colors` (by: "colors"): This share of the values, in percent, are color words, so the import places them in color groups.
          
          - `share` (integer · required)
        
        - `codes` (by: "codes"): This share of the values, in percent, are machine codes such as `HOME_FURNITURE_AND_DECOR`: data for rules, not words a shopper filters by, so the attribute is no filter.
          
          - `share` (integer · required)
        
        - `faceted` (by: "faceted"): The search pages filter by this option, so a query that names one of its values or groups is read as that filter (`detect_in_query`), within the token dimensions its facet already spends.
        
        - `carried` (by: "carried"): A facet: this many of the page's products carry the field, with this many different values.
          
          - `products` (integer · required)
          
          - `of` (integer · required)
          
          - `values` (integer · required)
        
        - `always` (by: "always"): Every shop offers it: relevance and price sorting, the price and category facets.
        
        - `offers` (by: "offers"): Offers carry what it reads, such as delivery days or sale prices, in this many items.
          
          - `count` (integer · required)
        
        - `signal` (by: "signal"): The catalog carries this signal in this many entities.
          
          - `signal` (string · required): The code of a signal, such as `sales_30d` or `rating`.
          
          - `entities` (integer · required)
        
        - `unique` (by: "unique"): This share of an identifier's values, in percent, of this many, belong to one product alone: a typo in one names another product, so the attribute is exempt from typos.
          
          - `share` (integer · required)
          
          - `values` (integer · required)
        
        - `shared` (by: "shared"): Only this share of an identifier's values, in percent, of this many, belong to one product alone: products share them, as cross-reference numbers are, so typos still find them.
          
          - `share` (integer · required)
          
          - `values` (integer · required)
        
        - `few` (by: "few"): Too few of an identifier's values, this many, tell whether they belong to one product each, so typos still find them.
          
          - `values` (integer · required)
      
      - `note` (string): Why the page starts in another order than the layout names, such as a sort `ranking.json` no longer defines.
    
    - `options` (object · required): The orders the page offers, as its answers list them.
      
      The orders a page offers.
      
      - `origin` (object · required): The list is taken whole from one place.
        
        Where a setting of a page comes from. A page takes each setting from the nearest category up the tree that sets it, else from the default layout of `categories.json`.
        
        - `page` (from: "page"): The page's own category sets it.
          
          - `derived` (boolean): The release leaves it out, so the index run derived it from the catalog.
        
        - `category` (from: "category"): The nearest category above the page that sets it, which the page inherits it from.
          
          - `category` (string · required): The id of a category node, such as `wohnen/sofas`: the merchant's id of a `category` entity.
          
          - `title` (string · required): The category's title in the locale, or its id where the catalog gives none.
          
          - `derived` (boolean): The release leaves it out, so the index run derived it from the catalog.
        
        - `default` (from: "default"): The default layout, which every page that sets none inherits.
          
          - `derived` (boolean): The release leaves it out, so the index run derived it from the catalog.
        
        - `built_in` (from: "built_in"): Nothing sets it, so the page has none, or starts by relevance.
      
      - `reason` (object): Why the index run chose them, where they are derived.
        
        What in the catalog decided a derived setting. Codes are stable, so the panel translates them.
        
        - `entities` (by: "entities"): The catalog holds entities of this built-in type, or the export makes them, such as categories from paths.
          
          - `count` (integer · required)
        
        - `language` (by: "language"): Most words that tell languages apart are this language's, in this share of them, in percent.
          
          - `locale` (string · required): A BCP 47 language tag such as `de`, `de-CH` or `en`. A locale falls back along its tag: `de-CH` to `de`.
          
          - `share` (integer · required)
        
        - `keyed` (by: "keyed"): Texts are keyed by this locale in this many entities.
          
          - `locale` (string · required): A BCP 47 language tag such as `de`, `de-CH` or `en`. A locale falls back along its tag: `de-CH` to `de`.
          
          - `entities` (integer · required)
        
        - `currency` (by: "currency"): Prices name this currency, written as in `written`, in this many values.
          
          - `currency` (string · required): An ISO 4217 currency code, such as `EUR`.
          
          - `written` (string · required)
          
          - `count` (integer · required)
        
        - `language_currency` (by: "language_currency"): No price names a currency, so the one the language usually pays in is taken.
          
          - `currency` (string · required): An ISO 4217 currency code, such as `EUR`.
          
          - `locale` (string · required): A BCP 47 language tag such as `de`, `de-CH` or `en`. A locale falls back along its tag: `de-CH` to `de`.
        
        - `values` (by: "values"): This share of the values, in percent, reads as this type; a quantity also names the unit most of them use.
          
          - `type` (string · required): - `boolean`
            
            - `text`: Free text: searchable, never a filter.
            
            - `identifier`: GTIN, MPN, ISBN and similar: exact match after normalization.
            
            - `option`: Enumerated values with labels, aliases, order, groups and swatches.
            
            - `number`: A number without a unit.
            
            - `quantity`: A number with a unit of one dimension.
            
            - `range`: A minimum and a maximum with a unit, such as age 3 to 6.
            
            - `date`: A date or a point in time.
          
          - `unit` (string): A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `mm`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `cm`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `m`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `in`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `ft`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `g`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `kg`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `lb`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `oz`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `ml`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `l`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `w`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `kw`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `wh`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `kwh`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `mah`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `v`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `lm`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `kelvin`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `celsius`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `hz`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `mb`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `gb`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `tb`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `day`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `month`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
            
            - `year`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
          
          - `share` (integer · required)
          
          - `values` (integer · required): Values read, and how many of them differ, up to a cap.
          
          - `distinct` (integer · required)
        
        - `varies` (by: "varies"): The variants carry the value in this many products, so it is the variants': an export puts there what differs inside a group, JSON Lines what the merchant wrote on the variants.
          
          - `products` (integer · required)
        
        - `lists` (by: "lists"): This many values arrive as lists, which only an attribute that takes several values reads.
          
          - `count` (integer · required)
        
        - `colors` (by: "colors"): This share of the values, in percent, are color words, so the import places them in color groups.
          
          - `share` (integer · required)
        
        - `codes` (by: "codes"): This share of the values, in percent, are machine codes such as `HOME_FURNITURE_AND_DECOR`: data for rules, not words a shopper filters by, so the attribute is no filter.
          
          - `share` (integer · required)
        
        - `faceted` (by: "faceted"): The search pages filter by this option, so a query that names one of its values or groups is read as that filter (`detect_in_query`), within the token dimensions its facet already spends.
        
        - `carried` (by: "carried"): A facet: this many of the page's products carry the field, with this many different values.
          
          - `products` (integer · required)
          
          - `of` (integer · required)
          
          - `values` (integer · required)
        
        - `always` (by: "always"): Every shop offers it: relevance and price sorting, the price and category facets.
        
        - `offers` (by: "offers"): Offers carry what it reads, such as delivery days or sale prices, in this many items.
          
          - `count` (integer · required)
        
        - `signal` (by: "signal"): The catalog carries this signal in this many entities.
          
          - `signal` (string · required): The code of a signal, such as `sales_30d` or `rating`.
          
          - `entities` (integer · required)
        
        - `unique` (by: "unique"): This share of an identifier's values, in percent, of this many, belong to one product alone: a typo in one names another product, so the attribute is exempt from typos.
          
          - `share` (integer · required)
          
          - `values` (integer · required)
        
        - `shared` (by: "shared"): Only this share of an identifier's values, in percent, of this many, belong to one product alone: products share them, as cross-reference numbers are, so typos still find them.
          
          - `share` (integer · required)
          
          - `values` (integer · required)
        
        - `few` (by: "few"): Too few of an identifier's values, this many, tell whether they belong to one product each, so typos still find them.
          
          - `values` (integer · required)
      
      - `options` ([array of SortOption](#SortOption) · required): In display order. A page that lists any offers the order it starts in too, marked `default`.
    
    - `choices` ([array of SortOption](#SortOption) · required): Every order a page can offer, `relevance` first, in the locale.

- `400` ([problem](/docs/reference/problems#400)): The body names a category the live catalog lacks, or a channel or locale the release lacks.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

- `422` ([problem](/docs/reference/problems#422)): The draft files make a release with violations; each names its file, a JSON pointer and what is wrong.

- `502` ([problem](/docs/reference/problems#502)): The Query API could not be reached.

- `503` ([problem](/docs/reference/problems#503)): Nothing is searchable yet.

## Search as a shopper would, in any context and at any time, with the trace

`POST /api/v1/preview/search`

The request as `POST /v1/search` takes it, answered against what searches read now, except that it may fix `time`: a scheduled rule or sale is checked on the day it starts. Without `time` it is answered now. The response always carries the trace, which names the rule behind every pin, boost and bury of each hit; the panel's playground shows the same answer.

### Body

[object](/docs/reference/query-api#search.body) · required

One search, category page or autocomplete request.

### Answers

- `200` ([object](/docs/reference/query-api#search.answer)): The answer, with the trace.

- `400` ([problem](/docs/reference/problems#400)): The request cannot be answered as sent, such as a channel or context key the release lacks.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

- `502` ([problem](/docs/reference/problems#502)): The Query API could not be reached.

- `503` ([problem](/docs/reference/problems#503)): Nothing is searchable yet, or the engine is unreachable.

```sh title="Terminal"
curl -s -H "Authorization: Bearer $key" -H 'Content-Type: application/json' \
  -d '{ "query": "graues Sofa", "redirect": false, "per_page": 2 }' $api/preview/search \
  | jq '{resolution, sections: [.sections[] | select(.hits != []) | {type, hits: [.hits[].entity]}]}'
```

```json title="Answer: 200 · 12 ms · release b25a6aaa"
{
  "resolution": {
    "category": "wohnen/sofas",
    "filters": {
      "color": "grey"
    },
    "text": "",
    "complete": true
  },
  "sections": [
    {
      "type": "product",
      "hits": [
        "product:SOFA-ASKA-2",
        "product:SOFA-NIKO-SCHLAF"
      ]
    }
  ]
}
```

## Open one of the shop's URLs as a shopper would, in any context and at any time

`POST /api/v1/preview/page`

A URL of the shop, such as a category page with its filters, answered as `GET /v1/resolve` answers it, with its results, in the channel, locale and context and at the time the body names. The page and its results always carry their traces; the panel's playground shows the same answer. With `files`, such as a draft's `categories.json`, the page is planned with them in place of the live release's own, so a draft's facets, sorting and URLs are seen before it is published.

### Body

A URL to preview as a shopper would meet it in a context and at a time, such as `{ "url": "/reifen?saison=winter", "channel": "de", "time": "2026-11-27T00:00:00+01:00" }`. The page always comes with its results and traces.

- `url` (string · required): The URL as `resolve` reads it: a path with its query string, or a whole URL, whose scheme and host are ignored.

- `channel` (string): The channel. Default: the release's first channel.

- `locale` (string): The locale. Default: the channel's first locale.

- `per_page` (integer · 1 to 100): Hits per page of a listing, up to the limit [`per_page`](/docs/reference/limits#per_page). Default: 24.

- `context` (map of strings): Declared context keys and their values, as a search request carries them, such as `{ "customer_group": "b2b" }`.

- `time` (string): The time the page is answered at. Default: now.

- `files` (map of strings): Release files by name that replace the live release's own for this preview alone, such as a draft's `categories.json`: the page is planned with them over the live catalog and index, so a draft's facets, sorting and URLs can be seen before it is published. What a file changes in the compiled index (a new attribute, a rule's pins) is not in the index until it is published, so such a preview shows the page as the live index can answer it.

### Answers

- `200` ([object](/docs/reference/query-api#resolve.answer)): The answer, with the trace.

- `400` ([problem](/docs/reference/problems#400)): The request cannot be answered as sent, such as a channel or context key the release lacks.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

- `422` ([problem](/docs/reference/problems#422)): The draft files make a release with violations; each names its file, a JSON pointer and what is wrong.

- `502` ([problem](/docs/reference/problems#502)): The Query API could not be reached.

- `503` ([problem](/docs/reference/problems#503)): Nothing is searchable yet, or the engine is unreachable.

## Say why one hit of a preview sits above another

`POST /api/v1/preview/compare`

The trace a preview answered with, sent back whole, the section and two places on its page. The answer names what put the higher hit above the other, from the trace alone and in the order the engine decides: a pin, boosts and buries that outweighed the text, or the first criterion they differ in, with each hit's value. Every hit of a preview also carries `why`, its own reasons, in the rank step.

### Body

Two hits of a trace's rank step to compare: which sits above the other, and why. The trace is the one a debug or preview response carried, sent back whole, so the answer is about exactly what was shown.

- `trace` ([object](/docs/reference/trace#search) · required)

- `type` (string · required): The section both hits are in.

- `positions` (array of integers · 2 items · required): Their places on the page, counted from 1, in either order.

### Answers

- `200` (object): Why one sits above the other.
  
  - `above` ([HitAt](#HitAt) · required): A hit of a section and its place on the page.
  
  - `below` ([HitAt](#HitAt) · required): A hit of a section and its place on the page.
  
  - `sentence` (string · required): The first thing that separated them, in a sentence.
  
  - `separated` (object · required): What put one hit above the other, in the order the engine decides: pins, then boosts and buries against the text, then the first criterion they differ in.
    
    - `pin` (by: "pin"): A rule pinned one of them.
      
      - `rule` (string · required): A rule's id, unique per release, such as `home/out-of-stock-last`. It appears in traces, tests, diffs and filter chips, so it is visible to storefronts and holds no secrets.
      
      - `description` (string · required)
      
      - `position` (integer · required)
      
      - `pinned` (string · required): One of `above` or `below`.
    
    - `weight` (by: "weight"): Boosts and buries weighed them apart: they count before every criterion but a better match of the query's words, and the lower one matches those as well or better.
      
      - `above` ([array of Weight](#Weight))
      
      - `below` ([array of Weight](#Weight))
    
    - `criterion` (by: "criterion"): The first criterion they differ in, with each one's value.
      
      - `above` (object · required): One criterion the engine compared hits by, with this hit's value. Hits are compared criterion by criterion in the order the engine ranks by, and the first criterion two hits differ in decides which comes first.
        
        - `words` (criterion: "words"): How many of the query's words it was found by, as typed, through a synonym or with a typo; more come first.
          
          - `matched` (integer · required)
          
          - `of` (integer · required)
        
        - `typos` (criterion: "typos"): How many typos it took to find those words; fewer come first.
          
          - `typos` (integer · required)
        
        - `sort` (criterion: "sort"): The sort the request chose, and the hit's value in it; a hit without a value comes last.
          
          - `sort` (string · required): The code of a sort option, such as `price_asc`. `relevance` is built in.
          
          - `by` (string · required): A field of an entity as search and result settings name it: a core field such as `title`, or an attribute as `attributes.<code>`; sort options also read `signals.<code>`.
          
          - `direction` (string · required): One of `asc` or `desc`.
          
          - `value` (any)
        
        - `business_score` (criterion: "business_score"): Its business score from 0 to 1; higher comes first.
          
          - `score` (number · required)
        
        - `proximity` (criterion: "proximity"): How close together the query's words stand in it, from 0 to 1; closer comes first.
          
          - `score` (number · required)
        
        - `fields` (criterion: "fields"): How early among the type's searched fields, and how early in a field, the words were found, from 0 to 1.
          
          - `score` (number · required)
        
        - `exactness` (criterion: "exactness"): Whether a field holds the query as a whole, starts with it, or neither, from 0 to 1.
          
          - `exact` (string · required): - `whole`: A field holds exactly the query.
            
            - `start`: A field starts with the query.
            
            - `no`: No field holds the query as it was written.
          
          - `score` (number · required)
      
      - `below` (object · required): One criterion the engine compared hits by, with this hit's value. Hits are compared criterion by criterion in the order the engine ranks by, and the first criterion two hits differ in decides which comes first.
        
        - `words` (criterion: "words"): How many of the query's words it was found by, as typed, through a synonym or with a typo; more come first.
          
          - `matched` (integer · required)
          
          - `of` (integer · required)
        
        - `typos` (criterion: "typos"): How many typos it took to find those words; fewer come first.
          
          - `typos` (integer · required)
        
        - `sort` (criterion: "sort"): The sort the request chose, and the hit's value in it; a hit without a value comes last.
          
          - `sort` (string · required): The code of a sort option, such as `price_asc`. `relevance` is built in.
          
          - `by` (string · required): A field of an entity as search and result settings name it: a core field such as `title`, or an attribute as `attributes.<code>`; sort options also read `signals.<code>`.
          
          - `direction` (string · required): One of `asc` or `desc`.
          
          - `value` (any)
        
        - `business_score` (criterion: "business_score"): Its business score from 0 to 1; higher comes first.
          
          - `score` (number · required)
        
        - `proximity` (criterion: "proximity"): How close together the query's words stand in it, from 0 to 1; closer comes first.
          
          - `score` (number · required)
        
        - `fields` (criterion: "fields"): How early among the type's searched fields, and how early in a field, the words were found, from 0 to 1.
          
          - `score` (number · required)
        
        - `exactness` (criterion: "exactness"): Whether a field holds the query as a whole, starts with it, or neither, from 0 to 1.
          
          - `exact` (string · required): - `whole`: A field holds exactly the query.
            
            - `start`: A field starts with the query.
            
            - `no`: No field holds the query as it was written.
          
          - `score` (number · required)
    
    - `tie` (by: "tie"): They are equal in everything the engine compares, so it keeps the order of its index.
    
    - `unknown` (by: "unknown"): By everything the trace records, the lower one comes first; what put the other above is not recorded.

- `400` ([problem](/docs/reference/problems#400)): The body is not a trace and two places.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

- `422` ([problem](/docs/reference/problems#422)): The trace's rank step holds no hit of the section at one of the places.

- `502` ([problem](/docs/reference/problems#502)): The Query API could not be reached.

## Say why a product is not on a preview's page, or where it is

`POST /api/v1/preview/find`

The request a preview's trace holds, its time included, and the entity to find, such as `{ "request": { "query": "ecksofa" }, "entity": "product:SOFA-MALMO" }`. The answer walks the stages a search passes it through and names the first that drops it: not in the live index, not searched on the page, not sold in the channel, outside the channel's assortment, outside the category, a rule's filter or hide, a filter the shopper chose or the query named, the query's words, which words match in which fields and which do not, or ranked after the page, with its place and why the page's last hit sits above it. Every answer ends in what to do: open the rule, remove the filter, add a synonym, pin it. The panel's playground shows the same answer.

### Body

An entity to find on the page a request answers, such as `{ "request": { "query": "ecksofa" }, "entity": "product:SOFA-MALMO" }`.

- `request` ([object](/docs/reference/query-api#search.body) · required): The request of the page, as a preview's trace holds it with its time, so the answer is about the page shown.

- `entity` (string · required): An entity named with its type, `type:id`, such as `product:SOFA-LUND-3`.

### Answers

- `200` (object): Where it is, or the stage that kept it off the page.
  
  - `release` (string · required): The configuration that answered.
  
  - `snapshot` (string · required): The catalog that was searched.
  
  - `entity` (string · required): An entity named with its type, `type:id`, such as `product:SOFA-LUND-3`.
  
  - `passed` (array of objects): The stages it passed, in the order a search runs them.
    
    A stage the entity passed, in a sentence.
    
    - `stage` (string · required): The stages a search passes an entity through on its way onto a page, in order.
      
      - `index`: The live index holds it.
      
      - `section`: The page searches its type.
      
      - `channel`: It is sold in the channel.
      
      - `assortment`: It is in the channel's assortment.
      
      - `category`: It is in the page's category, or the one the query named.
      
      - `rules`: No rule's filter or hide removes it.
      
      - `filters`: It matches the filters the shopper chose and the query named.
      
      - `text`: The query's words find it.
      
      - `rank`: Its place among the hits.
    
    - `sentence` (string · required): Such as "It is sold in the channel de."
  
  - `verdict` (object · required): The first stage that kept the entity off the page, with what it found, or the entity's place on it.
    
    - `index` (stage: "index"): The live index holds no entity of this type and id: the catalog snapshot lacks it, or a hide overlay removes it from every search. `overlays` are the release's hide overlays of its type that name it or may match it.
      
      - `overlays` (array of strings)
    
    - `section` (stage: "section"): The page searches no section of its type: a category page and a search without words list one type alone.
    
    - `redirect` (stage: "redirect"): A rule's redirect sends the shopper elsewhere, so the page searches nothing.
      
      - `rule` (string · required): A rule's id, unique per release, such as `home/out-of-stock-last`. It appears in traces, tests, diffs and filter chips, so it is visible to storefronts and holds no secrets.
      
      - `description` (string · required)
      
      - `url` (string · required)
    
    - `channel` (stage: "channel"): It is not sold in the channel: no offer of it is there.
      
      - `channel` (string · required): A channel's id, such as `de` or `ch`: a market or storefront.
    
    - `assortment` (stage: "assortment"): It has an offer in the channel, but the channel's assortment leaves it out: it does not match the selector.
      
      - `channel` (string · required): A channel's id, such as `de` or `ch`: a market or storefront.
      
      - `where` ([object](/docs/reference/query-api#Selector) · required): Picks entities (`where`). Attribute codes and the built-in fields `brand`, `price`, `on_sale`, `availability` and `delivery_days` are keys of the same object; `category` takes `is` or `within`.
        
        `{ "any": [{ "brand": "bosch" }, { "quality": "oe" }], "not": { "availability": "out_of_stock" } }`
    
    - `category` (stage: "category"): It is not in the category the page shows, or the one the query named.
      
      - `category` (string · required): The id of a category node, such as `wohnen/sofas`: the merchant's id of a `category` entity.
      
      - `words` (string): The query's words named the category; otherwise it is the page's own.
    
    - `rule_filter` (stage: "rule_filter"): A rule's filter narrows the section to what it is not.
      
      - `rule` (string · required): A rule's id, unique per release, such as `home/out-of-stock-last`. It appears in traces, tests, diffs and filter chips, so it is visible to storefronts and holds no secrets.
      
      - `description` (string · required)
      
      - `where` ([object](/docs/reference/query-api#Selector) · required): Picks entities (`where`). Attribute codes and the built-in fields `brand`, `price`, `on_sale`, `availability` and `delivery_days` are keys of the same object; `category` takes `is` or `within`.
        
        `{ "any": [{ "brand": "bosch" }, { "quality": "oe" }], "not": { "availability": "out_of_stock" } }`
    
    - `hidden` (stage: "hidden"): A rule hides it: by its id, or by a selector it matches.
      
      - `rule` (string · required): A rule's id, unique per release, such as `home/out-of-stock-last`. It appears in traces, tests, diffs and filter chips, so it is visible to storefronts and holds no secrets.
      
      - `description` (string · required)
      
      - `where` ([object](/docs/reference/query-api#Selector)): Picks entities (`where`). Attribute codes and the built-in fields `brand`, `price`, `on_sale`, `availability` and `delivery_days` are keys of the same object; `category` takes `is` or `within`.
        
        `{ "any": [{ "brand": "bosch" }, { "quality": "oe" }], "not": { "availability": "out_of_stock" } }`
    
    - `filter` (stage: "filter"): A filter the shopper chose, or the query's words named, keeps what it is not.
      
      - `where` ([object](/docs/reference/query-api#Selector) · required): With exactly one field or `category`, as the chip writes it.
      
      - `source` (string · required): - `shopper`: The shopper chose it.
        
        - `query`: The query named it.
        
        - `rule`: A rule added it.
      
      - `words` (string): The query's words that named it.
    
    - `together` (stage: "together"): It has each chosen value in some variant, but no variant has them all.
      
      - `where` ([object](/docs/reference/query-api#Selector) · required): Picks entities (`where`). Attribute codes and the built-in fields `brand`, `price`, `on_sale`, `availability` and `delivery_days` are keys of the same object; `category` takes `is` or `within`.
        
        `{ "any": [{ "brand": "bosch" }, { "quality": "oe" }], "not": { "availability": "out_of_stock" } }`
    
    - `text` (stage: "text"): The query's words do not find it.
      
      - `text` (string · required): The text the section searched, after rules and what the query named took their words.
      
      - `matched` (array of objects): The words that find it alone, with the fields they are in and the synonym that found them.
        
        A word of the query and how the hit was found by it.
        
        - `word` (string · required): The word as the engine reads the query.
        
        - `synonym` (string): The synonym it was found through, when the hit holds the synonym and not the word itself.
        
        - `entry` (string): The entry of `synonyms.json` that leads the word to its synonym, such as `de/groups/0`; with `synonym` only.
        
        - `typo` (string): The word of the hit it was found by with a typo, as its field writes it, such as `Bremsbelag` for `bremsbelg`.
        
        - `fields` (array of strings · required): The searched fields it was found in, in the type's order, such as `title`; `words` holds what the index adds, such as the titles of its categories.
      
      - `missing` (array of strings · required): The words no field of it holds, as typed, through a synonym or with a typo.
      
      - `held` (array of objects): Missing words a field of it holds where the search does not look for them: a field its type does not search, or an attribute exempt from typos that holds the word with a typo.
        
        A word of the query that a field of the entity holds where the search does not look for it.
        
        - `word` (string · required): The word as the engine reads the query.
        
        - `field` (string · required): The field, such as `attributes.mpn` or `brand`.
        
        - `holds` (string · required): The field's word, as it writes it, such as `1K0615301`.
        
        - `why` (string · required): Why the search does not find a word a field holds.
          
          - `not_searched`: The type does not search the field; it holds the word as typed.
          
          - `exempt_from_typos`: The attribute is exempt from typos, and holds the word with as many typos as its length would allow elsewhere.
    
    - `ranked` (stage: "ranked"): It is found, and ranks on another page: after this one, or before it on a later page.
      
      - `position` (integer · required): Its place among the hits, counted from 1.
      
      - `page` (integer · required): The page it is on, at the request's page size.
      
      - `why` (array of objects): Why it sits there, as a hit on its page would say.
        
        One reason a hit sits where it does, in a sentence and as data.
        
        - `sentence` (string · required): The reason in a sentence, such as "Pinned to position 1 by the rule “Sommer-Sale”."
        
        - `because` (object · required): - `pin` (kind: "pin"): A rule pinned it to its place, which comes before everything else; a paid pin names its campaign, and the sentence calls it a sponsored placement of that campaign.
            
            - `rule` (string · required): A rule's id, unique per release, such as `home/out-of-stock-last`. It appears in traces, tests, diffs and filter chips, so it is visible to storefronts and holds no secrets.
            
            - `description` (string · required)
            
            - `position` (integer · required)
            
            - `sponsored` (object): The campaign a paid placement belongs to: `{ "campaign": "Michelin spring" }`.
              
              - `campaign` (string · required): The merchant's name for it, which the campaign report counts by.
          
          - `weight` (kind: "weight"): A rule's boost or bury weighed it against the hits beside it.
            
            - `rule` (string · required): A rule's id, unique per release, such as `home/out-of-stock-last`. It appears in traces, tests, diffs and filter chips, so it is visible to storefronts and holds no secrets.
            
            - `description` (string · required)
            
            - `effect` (string · required): One of `resolve`, `rewrite`, `redirect`, `filter`, `hide`, `pin`, `boost`, `bury`, `sections` or `place`.
            
            - `factor` (number · required)
          
          - `named` (kind: "named"): Words of the query named something it is or has, which narrowed the results to it.
            
            - `words` (string · required)
            
            - `as` ([object](/docs/reference/query-api#Selector) · required): Picks entities (`where`). Attribute codes and the built-in fields `brand`, `price`, `on_sale`, `availability` and `delivery_days` are keys of the same object; `category` takes `is` or `within`.
              
              `{ "any": [{ "brand": "bosch" }, { "quality": "oe" }], "not": { "availability": "out_of_stock" } }`
            
            - `entry` (string · required): Where the meaning comes from, such as "the alias \"graues\" of the color group Grau".
            
            - `rule` (string): A rule's id, unique per release, such as `home/out-of-stock-last`. It appears in traces, tests, diffs and filter chips, so it is visible to storefronts and holds no secrets.
            
            - `pattern` (string)
            
            - `synonym` (string): The entry of `synonyms.json` that let the words name it, such as `de/groups/0`, when a synonym did.
          
          - `synonym` (kind: "synonym"): A word of the query found it only through a synonym, which the entry of `synonyms.json` holds.
            
            - `word` (string · required)
            
            - `synonym` (string · required)
            
            - `entry` (string): A synonym entry's place in `synonyms.json`: its language, its kind and its index there, such as `de/groups/0`, `de/one_way/2` or `de/never/0`. A delete moves the entries after it up, so a write names the draft version it read.
          
          - `text` (kind: "text"): How well it matches the query's text, and where.
            
            - `matched` (integer · required)
            
            - `of` (integer · required)
            
            - `typos` (integer · required)
            
            - `fields` (array of strings · required)
          
          - `sort` (kind: "sort"): The sort the request chose orders the page.
            
            - `sort` (string · required): The code of a sort option, such as `price_asc`. `relevance` is built in.
            
            - `by` (string · required): A field of an entity as search and result settings name it: a core field such as `title`, or an attribute as `attributes.<code>`; sort options also read `signals.<code>`.
            
            - `direction` (string · required): One of `asc` or `desc`.
            
            - `value` (any)
          
          - `business_score` (kind: "business_score"): Its business score orders it among the hits that match as well as it does; `signal` adds the most to it.
            
            - `score` (number · required)
            
            - `signal` (object): One signal of a hit's business score.
              
              - `signal` (string · required): The code of a signal, such as `sales_30d` or `rating`.
              
              - `value` (any): The signal as the catalog sends it, when it does.
              
              - `score` (number · required): Normalized to 0..1, the better the higher.
              
              - `weight` (number · required): Its weight in the type's business score.
      
      - `below` (object): Why the last hit of the asked page sits above it, when it ranks after the page.
        
        Why one hit sits above another of the same section.
        
        - `above` ([HitAt](#HitAt) · required): A hit of a section and its place on the page.
        
        - `below` ([HitAt](#HitAt) · required): A hit of a section and its place on the page.
        
        - `sentence` (string · required): The first thing that separated them, in a sentence.
        
        - `separated` (object · required): What put one hit above the other, in the order the engine decides: pins, then boosts and buries against the text, then the first criterion they differ in.
          
          - `pin` (by: "pin"): A rule pinned one of them.
            
            - `rule` (string · required): A rule's id, unique per release, such as `home/out-of-stock-last`. It appears in traces, tests, diffs and filter chips, so it is visible to storefronts and holds no secrets.
            
            - `description` (string · required)
            
            - `position` (integer · required)
            
            - `pinned` (string · required): One of `above` or `below`.
          
          - `weight` (by: "weight"): Boosts and buries weighed them apart: they count before every criterion but a better match of the query's words, and the lower one matches those as well or better.
            
            - `above` ([array of Weight](#Weight))
            
            - `below` ([array of Weight](#Weight))
          
          - `criterion` (by: "criterion"): The first criterion they differ in, with each one's value.
            
            - `above` (object · required): One criterion the engine compared hits by, with this hit's value. Hits are compared criterion by criterion in the order the engine ranks by, and the first criterion two hits differ in decides which comes first.
              
              - `words` (criterion: "words"): How many of the query's words it was found by, as typed, through a synonym or with a typo; more come first.
                
                - `matched` (integer · required)
                
                - `of` (integer · required)
              
              - `typos` (criterion: "typos"): How many typos it took to find those words; fewer come first.
                
                - `typos` (integer · required)
              
              - `sort` (criterion: "sort"): The sort the request chose, and the hit's value in it; a hit without a value comes last.
                
                - `sort` (string · required): The code of a sort option, such as `price_asc`. `relevance` is built in.
                
                - `by` (string · required): A field of an entity as search and result settings name it: a core field such as `title`, or an attribute as `attributes.<code>`; sort options also read `signals.<code>`.
                
                - `direction` (string · required): One of `asc` or `desc`.
                
                - `value` (any)
              
              - `business_score` (criterion: "business_score"): Its business score from 0 to 1; higher comes first.
                
                - `score` (number · required)
              
              - `proximity` (criterion: "proximity"): How close together the query's words stand in it, from 0 to 1; closer comes first.
                
                - `score` (number · required)
              
              - `fields` (criterion: "fields"): How early among the type's searched fields, and how early in a field, the words were found, from 0 to 1.
                
                - `score` (number · required)
              
              - `exactness` (criterion: "exactness"): Whether a field holds the query as a whole, starts with it, or neither, from 0 to 1.
                
                - `exact` (string · required): - `whole`: A field holds exactly the query.
                  
                  - `start`: A field starts with the query.
                  
                  - `no`: No field holds the query as it was written.
                
                - `score` (number · required)
            
            - `below` (object · required): One criterion the engine compared hits by, with this hit's value. Hits are compared criterion by criterion in the order the engine ranks by, and the first criterion two hits differ in decides which comes first.
              
              - `words` (criterion: "words"): How many of the query's words it was found by, as typed, through a synonym or with a typo; more come first.
                
                - `matched` (integer · required)
                
                - `of` (integer · required)
              
              - `typos` (criterion: "typos"): How many typos it took to find those words; fewer come first.
                
                - `typos` (integer · required)
              
              - `sort` (criterion: "sort"): The sort the request chose, and the hit's value in it; a hit without a value comes last.
                
                - `sort` (string · required): The code of a sort option, such as `price_asc`. `relevance` is built in.
                
                - `by` (string · required): A field of an entity as search and result settings name it: a core field such as `title`, or an attribute as `attributes.<code>`; sort options also read `signals.<code>`.
                
                - `direction` (string · required): One of `asc` or `desc`.
                
                - `value` (any)
              
              - `business_score` (criterion: "business_score"): Its business score from 0 to 1; higher comes first.
                
                - `score` (number · required)
              
              - `proximity` (criterion: "proximity"): How close together the query's words stand in it, from 0 to 1; closer comes first.
                
                - `score` (number · required)
              
              - `fields` (criterion: "fields"): How early among the type's searched fields, and how early in a field, the words were found, from 0 to 1.
                
                - `score` (number · required)
              
              - `exactness` (criterion: "exactness"): Whether a field holds the query as a whole, starts with it, or neither, from 0 to 1.
                
                - `exact` (string · required): - `whole`: A field holds exactly the query.
                  
                  - `start`: A field starts with the query.
                  
                  - `no`: No field holds the query as it was written.
                
                - `score` (number · required)
          
          - `tie` (by: "tie"): They are equal in everything the engine compares, so it keeps the order of its index.
          
          - `unknown` (by: "unknown"): By everything the trace records, the lower one comes first; what put the other above is not recorded.
    
    - `unreachable` (stage: "unreachable"): It is found, but more hits than pages reach rank above it, so its place is not known.
      
      - `reachable` (integer · required): How many hits pages reach.
      
      - `total` (integer · required): How many hits match.
    
    - `here` (stage: "here"): It is on the page.
      
      - `position` (integer · required)
  
  - `sentence` (string · required): The verdict in a sentence, ending in what to do.
  
  - `next` (array of objects): What the merchant can do to show it on the page, the likeliest first; none when it is there.
    
    One thing the merchant can do to show the entity on the page.
    
    - `check_catalog` (step: "check_catalog"): Check the entity in the shop's export: the snapshot was read from it.
    
    - `open_overlay` (step: "open_overlay"): Open the overlay that may hide it.
      
      - `overlay` (string · required): An id unique within its file, such as a search test's, an overlay's or a pattern's.
    
    - `search_words` (step: "search_words"): Search with words: other types show in sections of their own beside the listed one only then.
    
    - `add_offer` (step: "add_offer"): Give it an offer in the channel, in the shop's export.
      
      - `channel` (string · required): A channel's id, such as `de` or `ch`: a market or storefront.
    
    - `change_assortment` (step: "change_assortment"): Change the channel's assortment in `channels.json`, or the product's data it reads in the shop's export.
      
      - `channel` (string · required): A channel's id, such as `de` or `ch`: a market or storefront.
    
    - `assign_category` (step: "assign_category"): Assign it to the category, in the shop's export.
      
      - `category` (string · required): The id of a category node, such as `wohnen/sofas`: the merchant's id of a `category` entity.
    
    - `open_rule` (step: "open_rule"): Open the rule, to change its condition or what it keeps.
      
      - `rule` (string · required): A rule's id, unique per release, such as `home/out-of-stock-last`. It appears in traces, tests, diffs and filter chips, so it is visible to storefronts and holds no secrets.
      
      - `description` (string · required)
    
    - `remove_filter` (step: "remove_filter"): Remove the filter, as the shopper's chip does.
      
      - `where` ([object](/docs/reference/query-api#Selector) · required): Picks entities (`where`). Attribute codes and the built-in fields `brand`, `price`, `on_sale`, `availability` and `delivery_days` are keys of the same object; `category` takes `is` or `within`.
        
        `{ "any": [{ "brand": "bosch" }, { "quality": "oe" }], "not": { "availability": "out_of_stock" } }`
      
      - `source` (string · required): - `shopper`: The shopper chose it.
        
        - `query`: The query named it.
        
        - `rule`: A rule added it.
    
    - `add_synonym` (step: "add_synonym"): Add a synonym, so these words find what it holds.
      
      - `words` (array of strings · required)
    
    - `add_keywords` (step: "add_keywords"): Add these words to its search words with an overlay.
      
      - `words` (array of strings · required)
    
    - `pin` (step: "pin"): Pin it with a rule at this place, so it shows on the page whatever ranks above it.
      
      - `position` (integer · required)
    
    - `open_search_settings` (step: "open_search_settings"): Open how the type is searched: its fields in order, its typo settings and the attributes exempt from typos.
      
      - `type` (string · required): The code of an entity type, such as `product`, `category` or a merchant's own `store`.
  
  - `round_trip_ms` (number · required): The engine call that walked the stages, beside the page's own search: from sending it to reading its answer, in milliseconds. Debug only; no shopper's search makes it.

- `400` ([problem](/docs/reference/problems#400)): The request cannot be answered as sent, or the body names no entity.

- `401` ([problem](/docs/reference/problems#401)): The management key is missing or wrong.

- `502` ([problem](/docs/reference/problems#502)): The Query API could not be reached.

- `503` ([problem](/docs/reference/problems#503)): Nothing is searchable yet, or the engine is unreachable.

**Guide:** [Importing and mapping](/docs/importing) · [Releases](/docs/releases)

## `AppliedOffers`

The offer changes a run's indexes hold.

- `revision` (integer · required): The latest batch the indexes hold, which every trace names.

- `received_at` (string · required): When that batch arrived: the prices and stock searches show are at least as new.

- `products` (integer · required): The products of the catalog whose offers the changes reach.

## `Banner`

What a placement shows: a campaign's banner or a teaser to a page, with its words in every locale the release serves.

- `kind` (string · required): - `banner`: A campaign's banner, as wide as the results.
  
  - `teaser`: A card to a page, such as a buying guide, the size of a tile.

- `title` (string or map of strings · required): The headline, up to 200 characters.

- `text` (string or map of strings): A line or two under the title.

- `image` (object): A banner's image and the words that stand for it.
  
  - `url` (string · required): A path such as `/media/summer.jpg`, or a URL that starts with `https://`.
  
  - `alt` (string or map of strings · required): What the image shows, for a shopper who cannot see it.

- `link` (object): Where it leads, written as a redirect's target: an entity's page, such as `{ "to": "category:wohnen/sofas" }` or `{ "to": "content:sofa-ratgeber" }`, or a fixed URL, `{ "url": "/sale" }`. Without one it only informs.
  
  Where a redirect goes: an entity's page, whose URL follows the merchant's catalog, or a fixed URL.
  
  - `to` (string): An entity named with its type, `type:id`, such as `product:SOFA-LUND-3`.
  
  - `filters` ([object](/docs/reference/query-api#Selector)): With a category: the filters chosen on its page, as a request's filters name them.
  
  - `url` (string): A fixed URL: a path such as `/werkstatt`, or one that starts with `https://`.

## `BannerPlacement`

A banner at a place of the page: `{ "slot": "top", "banner": { ... } }`, or among the tiles, `{ "slot": "grid", "position": 5, "banner": { ... } }`.

- `slot` (string · required): Where on a page a banner sits.
  
  - `top`: Above the results, on the first page. Banners of several rules stand in rule order, the highest first.
  
  - `grid`: Among the tiles, before the one at its position, on the page that holds that tile.
  
  - `bottom`: After the results, on the last page. Banners of several rules stand in rule order, the highest first.

- `position` (integer · at least 1): With `grid`, and only there: the tile it sits before, counted from 1 across the pages of the listed section, whose tiles are the page's products, or its services on a workshop's page. Positions are unique within a rule; on a tie between rules the higher one takes the position and the other moves to the next free one, as pins do. A position past the last tile the pages reach shows nowhere, and the trace says why.

- `banner` ([Banner](#Banner) · required): What a placement shows: a campaign's banner or a teaser to a page, with its words in every locale the release serves.

## `Bucket`

A bucket from `from` (inclusive) to `to` (exclusive); either end may be open. Without `from`, a bucket counts everything up to its `to`, as in "up to 2 weeks"; without `to`, everything from its `from` on, as in "4 stars and more". Such open buckets may overlap.

- `from` (number)

- `to` (number)

- `label` (string or map of strings): A plain value, or a map from locale to value such as \{ "de": "Farbe", "en": "Color" \}.

## `CatalogFetch`

One fetch of the catalog source and how it ended.

- `id` (integer · required)

- `requested` (boolean): Someone asked for it; the schedule made the others. Left out for those.

- `started_at` (string · required): A point in time as RFC 3339 with an offset, such as `2026-11-27T00:00:00+01:00`.

- `finished_at` (string): Left out while it runs.

- `result` (string): Left out while it runs.
  
  - `unchanged`: The feed is the one fetched before, by the server's 304 or by its bytes, so nothing was queued.
  
  - `published`: The feed changed and its import is on its way live.
  
  - `drafted`: The feed changed and waits as a draft import.
  
  - `held_back`: The feed would remove half the live products or more, so it waits as a draft import, to be published with the number confirmed.
  
  - `failed`: Nothing changed for searches; `failure` says why.

- `failure` (string): Why it failed.
  
  - `address_refused`: The host is in a private, loopback or link-local network, which the stack does not fetch from.
  
  - `unreachable`: The host is unknown, or did not answer.
  
  - `timed_out`: The feed did not arrive in time.
  
  - `unauthorized`: The server answered 401 or 403: the credentials are wrong or missing.
  
  - `http_error`: The server answered with another error status, in `status`.
  
  - `too_many_redirects`: The URL redirects more than five times.
  
  - `too_large`: The feed is larger than the largest upload, 2 GB.
  
  - `empty`: The server sent nothing.
  
  - `unreadable`: The Query API cannot read the file.
  
  - `not_published`: The feed arrived, but publishing it was refused; the next fetch tries again.
  
  - `interrupted`: The fetch stopped halfway, such as when the control plane restarted.

- `status` (integer): The feed server's HTTP status, where it answered with an error.

- `message` (string): What a failed or held-back fetch means for the merchant, as a sentence.

- `bytes` (integer): The size of the feed, where it arrived.

- `import` ([Import](#Import)): The import a changed feed became: its state says whether it went live, and once published, its run.

## `ColumnRead`

A column's target with the options that say how its cells are read. The list is closed on purpose: no templates, expressions or combined columns until a real feed needs one.

- `to` (string · required): Where a column's values go: a field such as title or price, attributes.\<code\>, attributes.\* (the code made from what the column name's \* matched), attributes (with name or pairs), signals.\<code\>, or ignore.

- `split` (string or array of strings): Lists: the text between the values of one cell, such as `,` in "bild1.jpg,bild2.jpg" or `|` in "Holz|Metall"; or several, any of which separates them, such as `["|", ";"]` in "Blau;Schwarz|Grau".

- `levels` (string): Categories: the text between the levels of one path, such as ` > ` in "Wohnen \> Sofas".

- `values` (map of strings): Availability: the shop's words for each state, such as `{ "sofort lieferbar": "in_stock" }`. One of `in_stock`, `out_of_stock`, `preorder` or `backorder`.

- `unit` (string): Attributes: the unit of plain numbers in the column, such as `cm` for a column "Breite" holding "218".
  
  - `mm`: Attributes: the unit of plain numbers in the column, such as `cm` for a column "Breite" holding "218".
  
  - `cm`: Attributes: the unit of plain numbers in the column, such as `cm` for a column "Breite" holding "218".
  
  - `m`: Attributes: the unit of plain numbers in the column, such as `cm` for a column "Breite" holding "218".
  
  - `in`: Attributes: the unit of plain numbers in the column, such as `cm` for a column "Breite" holding "218".
  
  - `ft`: Attributes: the unit of plain numbers in the column, such as `cm` for a column "Breite" holding "218".
  
  - `g`: Attributes: the unit of plain numbers in the column, such as `cm` for a column "Breite" holding "218".
  
  - `kg`: Attributes: the unit of plain numbers in the column, such as `cm` for a column "Breite" holding "218".
  
  - `lb`: Attributes: the unit of plain numbers in the column, such as `cm` for a column "Breite" holding "218".
  
  - `oz`: Attributes: the unit of plain numbers in the column, such as `cm` for a column "Breite" holding "218".
  
  - `ml`: Attributes: the unit of plain numbers in the column, such as `cm` for a column "Breite" holding "218".
  
  - `l`: Attributes: the unit of plain numbers in the column, such as `cm` for a column "Breite" holding "218".
  
  - `w`: Attributes: the unit of plain numbers in the column, such as `cm` for a column "Breite" holding "218".
  
  - `kw`: Attributes: the unit of plain numbers in the column, such as `cm` for a column "Breite" holding "218".
  
  - `wh`: Attributes: the unit of plain numbers in the column, such as `cm` for a column "Breite" holding "218".
  
  - `kwh`: Attributes: the unit of plain numbers in the column, such as `cm` for a column "Breite" holding "218".
  
  - `mah`: Attributes: the unit of plain numbers in the column, such as `cm` for a column "Breite" holding "218".
  
  - `v`: Attributes: the unit of plain numbers in the column, such as `cm` for a column "Breite" holding "218".
  
  - `lm`: Attributes: the unit of plain numbers in the column, such as `cm` for a column "Breite" holding "218".
  
  - `kelvin`: Attributes: the unit of plain numbers in the column, such as `cm` for a column "Breite" holding "218".
  
  - `celsius`: Attributes: the unit of plain numbers in the column, such as `cm` for a column "Breite" holding "218".
  
  - `hz`: Attributes: the unit of plain numbers in the column, such as `cm` for a column "Breite" holding "218".
  
  - `mb`: Attributes: the unit of plain numbers in the column, such as `cm` for a column "Breite" holding "218".
  
  - `gb`: Attributes: the unit of plain numbers in the column, such as `cm` for a column "Breite" holding "218".
  
  - `tb`: Attributes: the unit of plain numbers in the column, such as `cm` for a column "Breite" holding "218".
  
  - `day`: Attributes: the unit of plain numbers in the column, such as `cm` for a column "Breite" holding "218".
  
  - `month`: Attributes: the unit of plain numbers in the column, such as `cm` for a column "Breite" holding "218".
  
  - `year`: Attributes: the unit of plain numbers in the column, such as `cm` for a column "Breite" holding "218".

- `locale` (string): Texts, categories and localized attributes: the locale the column is written in. Default: the source locale, the first channel's first locale.

- `channel` (string): Offer fields: the channel the column's prices or stock belong to. Default: the first channel in channels.json.

- `name` (string): Attributes written as name and value in two columns: the column holding each value's attribute name, with the same `*` as this column's name, such as `"Attribute * name"` beside `"Attribute * value(s)"`.

- `pairs` (string): Attributes written as pairs in one cell, such as "Farbe: Rot | Breite: 218 cm": the text between the pairs.

- `assign` (string): With `pairs`: the text between an attribute's name and its value. Default: `:`.

## `Condition`

A predicate over the request (`when`). Without a condition, a rule always matches.

`{ "on": "search", "query": { "contains": ["bremsen", "bremse"] } }`

- `query` (object): The query as typed, after normalization. Matching is literal: no typos, synonyms or plurals.
  
  How the query must look. A list of phrases means any of them.
  
  - `is` (string or array of strings): One value, or a list meaning any of them.
  
  - `contains` (string or array of strings): One value, or a list meaning any of them.
  
  - `starts_with` (string or array of strings): One value, or a list meaning any of them.
  
  - `empty` (boolean): True: nothing was typed. False: something was.

- `on` (string or array of strings): The surface the request comes from.
  
  - `search`: The search page's results.
  
  - `category_page`: A category's listing.
  
  - `autocomplete`: A search box's suggestions while the shopper types.

- `category` (object): The category page being browsed.
  
  A category, exactly or including everything below it.
  
  - `is` (string or array of strings): One value, or a list meaning any of them.
  
  - `within` (string or array of strings): One value, or a list meaning any of them.

- `resolved` ([ResolvedCondition](#ResolvedCondition)): What the query named. Rules that resolve or rewrite run before resolution and cannot read it.

- `channel` (string or array of strings): One value, or a list meaning any of them.

- `locale` (string or array of strings): One value, or a list meaning any of them.

- `context` (map of (string or array of strings)): Declared context keys and the values they must have, such as `{ "customer_group": "b2b" }`.

- `any` ([array of Condition](#Condition) · at least 1 item)

- `all` ([array of Condition](#Condition) · at least 1 item)

- `not` ([Condition](#Condition)): A predicate over the request (`when`). Without a condition, a rule always matches.
  
  `{ "on": "search", "query": { "contains": ["bremsen", "bremse"] } }`

## `Course`

The way a release goes live and why, as data and as a sentence.

- `way` (string · required): How a release goes live, from the cheapest to the dearest.
  
  - `switch`: The live indexes and the catalog dictionary stay, and the Query API loads the new release. It goes live at once.
  
  - `settings`: Settings the engine applies without reindexing, such as synonyms, are written to the live indexes, then the release is switched in. It goes live within moments.
  
  - `rebuild`: New indexes are built from the catalog beside the live ones and swapped in. The shop keeps answering with the live release meanwhile, and the time grows with the catalog.

- `because` (object · required): What decided the way. A file is named as the release writes it, such as `rules.json`, and a derived file by the name it would have.
  
  - `nothing_live` (id: "nothing_live"): Rebuild: no index run is live yet.
  
  - `new_catalog` (id: "new_catalog"): Rebuild: the catalog is not the live one's, so its documents are new.
  
  - `asked` (id: "asked"): Rebuild: the merchant asked for one, such as after the engine lost its data.
  
  - `out_of_date` (id: "out_of_date"): Rebuild: a sale window opened or closed, or an overlay ended, at `since`, after the live run built its documents.
    
    - `since` (string · required): A point in time as RFC 3339 with an offset, such as `2026-11-27T00:00:00+01:00`.
  
  - `engine_lacks_indexes` (id: "engine_lacks_indexes"): Rebuild: the engine no longer holds these live indexes.
    
    - `indexes` (array of strings · required)
  
  - `indexer_changed` (id: "indexer_changed"): Rebuild: the live run was built by another version of the indexer, or by one that recorded nothing to compare with. `was` is left out for the latter.
    
    - `was` (string)
    
    - `now` (string · required)
  
  - `documents_changed` (id: "documents_changed"): Rebuild: these files change what the engine's documents are built from or the shape of its indexes: types, channels, attributes, overlays, the feed mapping, the business score, the sort options or the facets pages count.
    
    - `files` (array of strings · required)
  
  - `settings_changed` (id: "settings_changed"): Settings: these files change only settings the engine applies without reindexing.
    
    - `files` (array of strings · required)
  
  - `serving_changed` (id: "serving_changed"): Switch: these files change only what the Query API reads: rules, the layout of pages, routes and redirects.
    
    - `files` (array of strings · required)
  
  - `unchanged` (id: "unchanged"): Switch: the live run already has this release and this catalog, so nothing changes.

- `sentence` (string · required): The same in a sentence, such as "Goes live at once: only rules.json and categories.json changed what the Query API reads."

## `Defaults`

The release files derived from a catalog, each with why every setting in it is what it is. Only files the release leaves out are derived; a file left empty here was not derived.

- `types` ([object](/docs/reference/release-files/types)): `types.json`: the entity types a release searches, and how each is listed, searched and returned.

- `channels` ([object](/docs/reference/release-files/channels)): `channels.json`: the channels a merchant sells in, and the context keys requests may carry.

- `attributes` ([object](/docs/reference/release-files/attributes)): `attributes.json`: what each attribute value means.

- `categories` ([object](/docs/reference/release-files/categories)): `categories.json`: the facets and sort options of search and category pages.

- `ranking` ([object](/docs/reference/release-files/ranking)): `ranking.json`: signals and weights, boost and bury strengths, sort options and section order.

- `rules` ([object](/docs/reference/release-files/rules)): `rules.json`: the rules in precedence order.

- `reasons` ([array of Derived](#Derived)): Why each derived setting is what it is, in the order of the files above.

## `Derived`

One derived setting and what in the catalog decided it.

- `file` (string · required): The release file the setting is written in, such as `attributes.json`.

- `setting` (string · required): The setting within it, as a person names it: an attribute's code such as `width`, a channel's id, a type's code, a sort option's or signal's code, `weights.<type>.<signal>`, `default.sort`, a rule's id, a facet as `default.facets.<field>` or `<category id>.facets.<field>`, and an identifier a type searches as `<type>.no_typos.<attribute>`.

- `reason` (object · required): What in the catalog decided a derived setting. Codes are stable, so the panel translates them.
  
  - `entities` (by: "entities"): The catalog holds entities of this built-in type, or the export makes them, such as categories from paths.
    
    - `count` (integer · required)
  
  - `language` (by: "language"): Most words that tell languages apart are this language's, in this share of them, in percent.
    
    - `locale` (string · required): A BCP 47 language tag such as `de`, `de-CH` or `en`. A locale falls back along its tag: `de-CH` to `de`.
    
    - `share` (integer · required)
  
  - `keyed` (by: "keyed"): Texts are keyed by this locale in this many entities.
    
    - `locale` (string · required): A BCP 47 language tag such as `de`, `de-CH` or `en`. A locale falls back along its tag: `de-CH` to `de`.
    
    - `entities` (integer · required)
  
  - `currency` (by: "currency"): Prices name this currency, written as in `written`, in this many values.
    
    - `currency` (string · required): An ISO 4217 currency code, such as `EUR`.
    
    - `written` (string · required)
    
    - `count` (integer · required)
  
  - `language_currency` (by: "language_currency"): No price names a currency, so the one the language usually pays in is taken.
    
    - `currency` (string · required): An ISO 4217 currency code, such as `EUR`.
    
    - `locale` (string · required): A BCP 47 language tag such as `de`, `de-CH` or `en`. A locale falls back along its tag: `de-CH` to `de`.
  
  - `values` (by: "values"): This share of the values, in percent, reads as this type; a quantity also names the unit most of them use.
    
    - `type` (string · required): - `boolean`
      
      - `text`: Free text: searchable, never a filter.
      
      - `identifier`: GTIN, MPN, ISBN and similar: exact match after normalization.
      
      - `option`: Enumerated values with labels, aliases, order, groups and swatches.
      
      - `number`: A number without a unit.
      
      - `quantity`: A number with a unit of one dimension.
      
      - `range`: A minimum and a maximum with a unit, such as age 3 to 6.
      
      - `date`: A date or a point in time.
    
    - `unit` (string): A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `mm`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `cm`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `m`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `in`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `ft`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `g`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `kg`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `lb`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `oz`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `ml`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `l`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `w`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `kw`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `wh`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `kwh`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `mah`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `v`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `lm`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `kelvin`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `celsius`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `hz`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `mb`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `gb`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `tb`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `day`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `month`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `year`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
    
    - `share` (integer · required)
    
    - `values` (integer · required): Values read, and how many of them differ, up to a cap.
    
    - `distinct` (integer · required)
  
  - `varies` (by: "varies"): The variants carry the value in this many products, so it is the variants': an export puts there what differs inside a group, JSON Lines what the merchant wrote on the variants.
    
    - `products` (integer · required)
  
  - `lists` (by: "lists"): This many values arrive as lists, which only an attribute that takes several values reads.
    
    - `count` (integer · required)
  
  - `colors` (by: "colors"): This share of the values, in percent, are color words, so the import places them in color groups.
    
    - `share` (integer · required)
  
  - `codes` (by: "codes"): This share of the values, in percent, are machine codes such as `HOME_FURNITURE_AND_DECOR`: data for rules, not words a shopper filters by, so the attribute is no filter.
    
    - `share` (integer · required)
  
  - `faceted` (by: "faceted"): The search pages filter by this option, so a query that names one of its values or groups is read as that filter (`detect_in_query`), within the token dimensions its facet already spends.
  
  - `carried` (by: "carried"): A facet: this many of the page's products carry the field, with this many different values.
    
    - `products` (integer · required)
    
    - `of` (integer · required)
    
    - `values` (integer · required)
  
  - `always` (by: "always"): Every shop offers it: relevance and price sorting, the price and category facets.
  
  - `offers` (by: "offers"): Offers carry what it reads, such as delivery days or sale prices, in this many items.
    
    - `count` (integer · required)
  
  - `signal` (by: "signal"): The catalog carries this signal in this many entities.
    
    - `signal` (string · required): The code of a signal, such as `sales_30d` or `rating`.
    
    - `entities` (integer · required)
  
  - `unique` (by: "unique"): This share of an identifier's values, in percent, of this many, belong to one product alone: a typo in one names another product, so the attribute is exempt from typos.
    
    - `share` (integer · required)
    
    - `values` (integer · required)
  
  - `shared` (by: "shared"): Only this share of an identifier's values, in percent, of this many, belong to one product alone: products share them, as cross-reference numbers are, so typos still find them.
    
    - `share` (integer · required)
    
    - `values` (integer · required)
  
  - `few` (by: "few"): Too few of an identifier's values, this many, tell whether they belong to one product each, so typos still find them.
    
    - `values` (integer · required)

## `DerivedValue`

An option value whose meaning the import derived instead of reading it from attributes.json: a value the feed brought, or a color group the built-in colors gave a value.

- `attribute` (string · required): The code of an attribute definition, such as `color` or `seat_height`. The reserved words `any`, `all`, `not`, `category`, `brand`, `price`, `on_sale`, `availability`, `delivery_days` and `rating` cannot be attribute codes.

- `value` (string · required): The code of an option value or option group, such as `grey` or `160x230`.

- `label` (string · required): The feed's spelling as first seen, which shoppers see for a value attributes.json does not list.

- `listed` (boolean): attributes.json lists the value without a group, and the built-in colors gave it one.

- `count` (integer · required): Entities and variants that carry the value.

- `groups` (array of strings): The groups it shows under; a value between two colors, such as petrol, may have two.

- `placed` (object): How the built-in colors chose the group, for attributes with color groups.
  
  The stage of the built-in colors that placed a value in a group, or that none did.
  
  - `name` (by: "name"): The whole name is a color the built-in table knows, such as "Anthrazit".
  
  - `word` (by: "word"): The color word inside the name that decides, such as "basalt" in "Basaltgrau".
    
    - `word` (string · required)
  
  - `swatch` (by: "swatch"): The group whose center lies nearest to the value's swatch in OKLab, at this distance.
    
    - `swatch` (string · required): A swatch color in hexadecimal notation, such as `#C62828`.
    
    - `distance` (number · required)
  
  - `nothing` (by: "nothing"): No stage placed it: the name holds no color word, or words of two groups, and the value has no swatch.

## `Effects`

What a rule does. Understand-phase effects (`resolve`, `rewrite`) run before the query is resolved; `redirect` ends planning; the rest shape the results, and `place` puts banners beside them.

- `resolve` (array of objects): Decides what an ambiguous term means. Per term, the higher rule decides.
  
  What one term means: values such as `{ "term": "puma", "as": { "brand": "puma" } }`, a category such as `"as": { "category": "parts/brakes" }`, or `"as": "text"` to keep it as text.
  
  - `term` (string · required)
  
  - `as` (string or map of (boolean, number or string) · required): One of `text`.

- `rewrite` (object): Removes words from the query before it is resolved and searched. Removals of all rules are united.
  
  - `remove` (array of strings · required)

- `redirect` (object): Sends the shopper elsewhere. The highest redirect wins and ends planning.
  
  Where a redirect goes: an entity's page, whose URL follows the merchant's catalog, or a fixed URL.
  
  - `to` (string): An entity named with its type, `type:id`, such as `product:SOFA-LUND-3`.
  
  - `filters` ([object](/docs/reference/query-api#Selector)): With a category: the filters chosen on its page, as a request's filters name them.
  
  - `url` (string): A fixed URL: a path such as `/werkstatt`, or one that starts with `https://`.

- `filter` (object): Narrows the results. Shoppers see it as a chip they can remove.
  
  A filter a rule adds, optionally only for one type's section.
  
  - `type` (string): The code of an entity type, such as `product`, `category` or a merchant's own `store`.
  
  - `where` ([object](/docs/reference/query-api#Selector) · required): Picks entities (`where`). Attribute codes and the built-in fields `brand`, `price`, `on_sale`, `availability` and `delivery_days` are keys of the same object; `category` takes `is` or `within`.
    
    `{ "any": [{ "brand": "bosch" }, { "quality": "oe" }], "not": { "availability": "out_of_stock" } }`

- `hide` ([array of Hide](#Hide)): Removes entities from the results. Hide beats pin.

- `pin` ([array of Pin](#Pin)): Puts entities at fixed positions, within every filter.

- `boost` ([array of Shift](#Shift)): Moves entities up, within relevance.

- `bury` ([array of Shift](#Shift)): Moves entities down, within relevance.

- `sections` (array of strings): The order of sections. Types not listed follow in the release's order.

- `place` ([array of BannerPlacement](#BannerPlacement)): Puts banners and teasers above, among or below the results. A placement is not a hit: it changes no total, facet, page size or order of hits.

## `ExemptAttribute`

An attribute, exempt from typos or left open to them.

- `attribute` (string · required): The code of an attribute definition, such as `color` or `seat_height`. The reserved words `any`, `all`, `not`, `category`, `brand`, `price`, `on_sale`, `availability`, `delivery_days` and `rating` cannot be attribute codes.

- `label` (string · required): Its name in the locale.

- `reason` (object): Why the run decided so, where the list is derived.
  
  What in the catalog decided a derived setting. Codes are stable, so the panel translates them.
  
  - `entities` (by: "entities"): The catalog holds entities of this built-in type, or the export makes them, such as categories from paths.
    
    - `count` (integer · required)
  
  - `language` (by: "language"): Most words that tell languages apart are this language's, in this share of them, in percent.
    
    - `locale` (string · required): A BCP 47 language tag such as `de`, `de-CH` or `en`. A locale falls back along its tag: `de-CH` to `de`.
    
    - `share` (integer · required)
  
  - `keyed` (by: "keyed"): Texts are keyed by this locale in this many entities.
    
    - `locale` (string · required): A BCP 47 language tag such as `de`, `de-CH` or `en`. A locale falls back along its tag: `de-CH` to `de`.
    
    - `entities` (integer · required)
  
  - `currency` (by: "currency"): Prices name this currency, written as in `written`, in this many values.
    
    - `currency` (string · required): An ISO 4217 currency code, such as `EUR`.
    
    - `written` (string · required)
    
    - `count` (integer · required)
  
  - `language_currency` (by: "language_currency"): No price names a currency, so the one the language usually pays in is taken.
    
    - `currency` (string · required): An ISO 4217 currency code, such as `EUR`.
    
    - `locale` (string · required): A BCP 47 language tag such as `de`, `de-CH` or `en`. A locale falls back along its tag: `de-CH` to `de`.
  
  - `values` (by: "values"): This share of the values, in percent, reads as this type; a quantity also names the unit most of them use.
    
    - `type` (string · required): - `boolean`
      
      - `text`: Free text: searchable, never a filter.
      
      - `identifier`: GTIN, MPN, ISBN and similar: exact match after normalization.
      
      - `option`: Enumerated values with labels, aliases, order, groups and swatches.
      
      - `number`: A number without a unit.
      
      - `quantity`: A number with a unit of one dimension.
      
      - `range`: A minimum and a maximum with a unit, such as age 3 to 6.
      
      - `date`: A date or a point in time.
    
    - `unit` (string): A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `mm`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `cm`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `m`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `in`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `ft`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `g`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `kg`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `lb`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `oz`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `ml`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `l`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `w`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `kw`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `wh`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `kwh`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `mah`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `v`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `lm`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `kelvin`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `celsius`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `hz`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `mb`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `gb`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `tb`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `day`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `month`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
      
      - `year`: A unit OrbSearch converts between. The registry is built in: conversion factors are physics, not configuration.
    
    - `share` (integer · required)
    
    - `values` (integer · required): Values read, and how many of them differ, up to a cap.
    
    - `distinct` (integer · required)
  
  - `varies` (by: "varies"): The variants carry the value in this many products, so it is the variants': an export puts there what differs inside a group, JSON Lines what the merchant wrote on the variants.
    
    - `products` (integer · required)
  
  - `lists` (by: "lists"): This many values arrive as lists, which only an attribute that takes several values reads.
    
    - `count` (integer · required)
  
  - `colors` (by: "colors"): This share of the values, in percent, are color words, so the import places them in color groups.
    
    - `share` (integer · required)
  
  - `codes` (by: "codes"): This share of the values, in percent, are machine codes such as `HOME_FURNITURE_AND_DECOR`: data for rules, not words a shopper filters by, so the attribute is no filter.
    
    - `share` (integer · required)
  
  - `faceted` (by: "faceted"): The search pages filter by this option, so a query that names one of its values or groups is read as that filter (`detect_in_query`), within the token dimensions its facet already spends.
  
  - `carried` (by: "carried"): A facet: this many of the page's products carry the field, with this many different values.
    
    - `products` (integer · required)
    
    - `of` (integer · required)
    
    - `values` (integer · required)
  
  - `always` (by: "always"): Every shop offers it: relevance and price sorting, the price and category facets.
  
  - `offers` (by: "offers"): Offers carry what it reads, such as delivery days or sale prices, in this many items.
    
    - `count` (integer · required)
  
  - `signal` (by: "signal"): The catalog carries this signal in this many entities.
    
    - `signal` (string · required): The code of a signal, such as `sales_30d` or `rating`.
    
    - `entities` (integer · required)
  
  - `unique` (by: "unique"): This share of an identifier's values, in percent, of this many, belong to one product alone: a typo in one names another product, so the attribute is exempt from typos.
    
    - `share` (integer · required)
    
    - `values` (integer · required)
  
  - `shared` (by: "shared"): Only this share of an identifier's values, in percent, of this many, belong to one product alone: products share them, as cross-reference numbers are, so typos still find them.
    
    - `share` (integer · required)
    
    - `values` (integer · required)
  
  - `few` (by: "few"): Too few of an identifier's values, this many, tell whether they belong to one product each, so typos still find them.
    
    - `values` (integer · required)

## `ExemptAttributes`

The attributes a type's words find only as written or by their start.

- `source` (string · required): Where a search setting comes from.
  
  - `set`: The merchant set it, in the release's or the draft's `types.json`.
  
  - `derived`: The release leaves it out, so the index run derived it from the catalog: the import's default.
  
  - `built_in`: Nothing sets it: OrbSearch's own default.

- `attributes` ([array of ExemptAttribute](#ExemptAttribute) · required)

- `open` ([array of ExemptAttribute](#ExemptAttribute)): The identifier attributes the type searches that the run left open to typos, each with why: what the catalog does not tell stays open. Only where the list is derived.

## `FacetValue`

- `value` (boolean, number or string · required): What a request's `filters` name to choose it: a value or group code, a number, `true`, a category id, or a bucket's code written as its bounds, such as `100-300`, `-4` or `4-`.

- `label` (string · required)

- `count` (integer · required)

- `bounds` ([object](/docs/reference/query-api#Comparison)): A bucket's bounds, such as `{ "gte": 100, "lt": 300 }`; selecting the bucket filters the field by them.

- `parent` (boolean, number or string): In a hierarchical facet, the value one level up.

- `selected` (boolean)

- `swatch` (string)

- `image` (string): A swatch image or pattern, or a brand's logo where the facet shows images; its URL.

- `description` (string): What the value means, read with it.

## `FeedReport`

How an export was read and mapped: what the import recognized, whether `feed.json` or the derived mapping placed the columns, and the columns whose values went nowhere.

- `format` ([Format](#Format) · required): The file as the import read it: its kind and, for text and spreadsheets, its encoding, delimiter, sheet and header row.

- `mapping` (string · required): Who placed an export's columns.
  
  - `derived`: The release has no `feed.json`; the import derived the mapping from the columns and their values.
  
  - `file`: The release's `feed.json`, exactly as written.
  
  - `native`: OrbSearch's own JSON Lines, which need no mapping.

- `unmapped` (array of strings): Columns `feed.json` does not name; their values were left out.

- `ignored` (array of strings): Columns left out on purpose: mapped to `ignore`, or by the derived mapping as shipping, tax and ads data, or because no row fills them.

## `Format`

How a file is read: its kind, and for text and spreadsheets the details a guess can get wrong. The import recognizes each from the bytes; a value here pins it.

- `kind` (string): The kinds of files the import reads. Any of them may arrive gzipped.
  
  - `jsonl`: OrbSearch's own catalog: one entity per line as JSON. It needs no mapping.
  
  - `csv`: Delimited text: CSV, TSV and TXT, Merchant Center's TSV included.
  
  - `xlsx`: An Excel workbook.
  
  - `xml`: A Merchant Center feed: RSS 2.0 or Atom with the `g:` namespace.
  
  - `json`: JSON records of a shape of their own, as an array or one object per line: nested objects are read as columns such as `dimensions.width`, arrays of plain values as lists.

- `delimiter` (string): Delimited text: the character between cells.
  
  - `,`: Delimited text: the character between cells.
  
  - `;`: Delimited text: the character between cells.
  
  - `	`: Delimited text: the character between cells.
  
  - `|`: Delimited text: the character between cells.

- `encoding` (string): Text: the character encoding.
  
  - `utf-8`
  
  - `utf-16le`
  
  - `utf-16be`
  
  - `windows-1252`: What Excel on Windows writes for German text; ISO 8859-1 reads the same.

- `decimal` (string): The decimal mark of numbers written as text, such as `,` in "1.099,00". Without it, each column's numbers tell.
  
  - `,`: The decimal mark of numbers written as text, such as `,` in "1.099,00". Without it, each column's numbers tell.
  
  - `.`: The decimal mark of numbers written as text, such as `,` in "1.099,00". Without it, each column's numbers tell.

- `sheet` (string): Spreadsheets: the sheet to read by its name. Default: the first.

- `header` (integer): Text and spreadsheets: the row holding the column names, counted from 1. Without it, the first row that looks like a header is taken, so title rows above it are skipped.

## `Hide`

The entities an effect is about: one entity, several, or all that match a selector, optionally of one type.

- `entity` (string): An entity named with its type, `type:id`, such as `product:SOFA-LUND-3`.

- `entities` (array of strings)

- `where` ([object](/docs/reference/query-api#Selector)): Picks entities (`where`). Attribute codes and the built-in fields `brand`, `price`, `on_sale`, `availability` and `delivery_days` are keys of the same object; `category` takes `is` or `within`.
  
  `{ "any": [{ "brand": "bosch" }, { "quality": "oe" }], "not": { "availability": "out_of_stock" } }`

- `type` (string): With `where`: only entities of this type.

## `HitAt`

A hit of a section and its place on the page.

- `entity` (string · required): An entity named with its type, `type:id`, such as `product:SOFA-LUND-3`.

- `variant` (string): The merchant's id of an entity, unique per type, such as `SOFA-LUND-3`. It travels unchanged; OrbSearch never rewrites it.

- `position` (integer · required)

## `Import`

An export on its way to live: the file as the shop wrote it, the release files it is read with, and once published, the release and the index run that make it live. Imports are never deleted, so every export that went live can go live again while its file is kept.

- `id` (integer · required)

- `state` (string · required): Where an import stands.
  
  - `draft`: Kept, not published: it can be inspected, corrected, published or discarded.
  
  - `going_live`: Published; its index run is queued or running.
  
  - `live`: Searches read it.
  
  - `replaced`: It was live, or on its way, until a later publish took its place; publishing it again goes back to it.
  
  - `failed`: Its index run failed, and `run.error` says why. What was live before stays live.
  
  - `discarded`: Put aside without going live.

- `version` (string · required): The version a write to this draft names. It changes with every change of the files and with the release the draft builds on.

- `export` ([ImportExport](#ImportExport) · required): The export of an import: the file's name as it arrived and the snapshot that keeps its bytes.

- `base_release_id` (string): The release the import was built on: for a draft, the one published when its export arrived, though a draft always builds on the release published now, so publishing it never undoes a release published since; once published, the one it went live on. Left out before any release was published.

- `files` (map of strings): The release files the import reads its export with instead of the base release's, by name, in the canonical form the Query API wrote; left out when it changes none.

- `release_id` (string): Once published: the release its files made.

- `run` ([IndexRun](#IndexRun)): Once published: the index run that makes it live, the latest if it was published more than once.

- `created_at` (string · required): A point in time as RFC 3339 with an offset, such as `2026-11-27T00:00:00+01:00`.

- `published_at` (string): When it was last published.

- `discarded_at` (string): A point in time as RFC 3339 with an offset, such as `2026-11-27T00:00:00+01:00`.

## `ImportExport`

The export of an import: the file's name as it arrived and the snapshot that keeps its bytes.

- `name` (string): The file's name, as the panel or the `name` parameter gave it.

- `snapshot_id` (string · required): The id of a catalog snapshot. A snapshot is named by its content and never changes.

- `bytes` (integer · required)

- `removed_at` (string): When the indexer's clean-up removed the file. The import can no longer be inspected or published again until the same export is sent again.

## `IndexRun`

A snapshot and a release compiled into the engine; the latest that succeeded is live.

- `id` (integer · required)

- `state` (string · required): Where an index run stands.
  
  - `queued`: Waiting for an indexer.
  
  - `running`: An indexer is building the indexes.
  
  - `succeeded`: The indexes are live: searches read this run's snapshot and release.
  
  - `failed`: The run stopped; `error` says why. Nothing it built went live.
  
  - `superseded`: A newer run replaced it: one was queued while it waited, or went live before it finished. Its indexes, if any, were dropped.

- `trigger` (string): What queued the run; left out for runs queued before triggers were recorded. Its report's `course.cause` says something else: why the run took the way it took live.
  
  - `upload`: A catalog sent to `PUT /api/v1/catalog`.
  
  - `import`: An import published.
  
  - `release`: A release published, or published again to roll back.
  
  - `rebuild`: A rebuild asked for with `POST /api/v1/index-runs`.
  
  - `refresh`: The indexer itself: a sale window opened or closed, an overlay ended, or another version of it built the live indexes.
  
  - `fetch`: A fetch of the catalog source found its feed changed.

- `snapshot_id` (string · required): The id of a catalog snapshot. A snapshot is named by its content and never changes.

- `release_id` (string · required): The id of a release. A release is named by its content and never changes.

- `attempts` (integer · required): How often an indexer took it up; a run whose indexer died is taken up again, three times at most.

- `progress` ([RunProgress](#RunProgress)): How far it got: while it runs, and for a failed run the step it failed in. Left out for any other run.

- `report` ([RunReport](#RunReport)): What the run did, once it finished.

- `error` (string): Why it failed, as a sentence.

- `created_at` (string · required): A point in time as RFC 3339 with an offset, such as `2026-11-27T00:00:00+01:00`.

- `started_at` (string): A point in time as RFC 3339 with an offset, such as `2026-11-27T00:00:00+01:00`.

- `finished_at` (string): A point in time as RFC 3339 with an offset, such as `2026-11-27T00:00:00+01:00`.

- `live_at` (string): When its indexes became the ones searches read.

- `live` (boolean): Searches read this run now, the latest that succeeded. Left out for any other run. A run that changed nothing says so in its report: its course is `unchanged`.

- `snapshot` ([Snapshot](#Snapshot)): Its snapshot, whose `removed_at` says whether its file is still kept.

- `release` ([StoredRelease](#StoredRelease)): On the live run: its release.

## `ListedDictionary`

The entries of one language: its groups, then its one-way entries, then the words never merged, each in file order.

- `locale` (string · required): A BCP 47 language tag such as `de`, `de-CH` or `en`. A locale falls back along its tag: `de-CH` to `de`.

- `dormant` (boolean): No channel serves the language, so its synonyms wait until one does. A language a channel serves as `de-CH` reads the `de` dictionary when it has none of its own.

- `entries` ([array of ListedSynonym](#ListedSynonym) · required)

## `ListedRule`

One rule with what a merchant wants to know of it.

- `id` (string · required): A rule's id, unique per release, such as `home/out-of-stock-last`. It appears in traces, tests, diffs and filter chips, so it is visible to storefronts and holds no secrets.

- `position` (integer · required): Its place in the order, counted from 1. The higher rule wins where two effects exclude each other.

- `description` (string · required): The rule's name, one line.

- `summary` (string · required): What it does and when, in one line, such as `Pins Vidar Ecksofa to 1 for "sofa"`. Products are named by their title where the catalog holds them, else by their id.

- `enabled` (boolean · required): A disabled rule is not evaluated.

- `origin` (object): Where the rule came from; left out for a rule the merchant made.
  
  Where an imported rule or overlay came from.
  
  - `import` (string · required): What it was imported from, such as the previous search's export.
  
  - `ref` (string · required)

- `surfaces` (array of strings · required): Where it can act, from its condition: the surfaces it names, else the category page if it names a category, else every surface.
  
  - `search`: The search page's results.
  
  - `category_page`: A category's listing.
  
  - `autocomplete`: A search box's suggestions while the shopper types.

- `state` (object · required): A rule's state at the list's time, as data and as a sentence.
  
  - `active` (id: "active"): It applies to the requests its condition matches.
    
    - `until` (string): When its window closes; left out for a rule without an end.
  
  - `scheduled` (id: "scheduled"): Its window has not opened yet.
    
    - `from` (string · required): A point in time as RFC 3339 with an offset, such as `2026-11-27T00:00:00+01:00`.
    
    - `until` (string): A point in time as RFC 3339 with an offset, such as `2026-11-27T00:00:00+01:00`.
  
  - `expired` (id: "expired"): Its window has closed.
    
    - `until` (string · required): A point in time as RFC 3339 with an offset, such as `2026-11-27T00:00:00+01:00`.
  
  - `disabled` (id: "disabled"): It is switched off.
  
  - `dormant` (id: "dormant"): It acts on entities alone, and every one of them is `gone` from the catalog, so it does nothing until one comes back.

- `conflicts` (array of objects): What other rules take from it, in rule order; none when nothing does. They come from higher rules, but for a hide, which counts wherever it stands.
  
  What another rule takes from a rule where their effects exclude each other, as data and as a sentence. It holds where both rules can match one request: conditions that cannot meet, such as two different query phrases, never conflict.
  
  - `redirect` (id: "redirect"): The highest redirect wins and ends planning, so this redirect never sends a shopper that the higher one does not.
    
    - `by` (string · required): A rule's id, unique per release, such as `home/out-of-stock-last`. It appears in traces, tests, diffs and filter chips, so it is visible to storefronts and holds no secrets.
  
  - `term` (id: "term"): The higher rule decides what the term means.
    
    - `term` (string · required)
    
    - `by` (string · required): A rule's id, unique per release, such as `home/out-of-stock-last`. It appears in traces, tests, diffs and filter chips, so it is visible to storefronts and holds no secrets.
  
  - `pinned` (id: "pinned"): The higher rule pins the same entity, and its pin counts.
    
    - `entity` (string · required): An entity named with its type, `type:id`, such as `product:SOFA-LUND-3`.
    
    - `by` (string · required): A rule's id, unique per release, such as `home/out-of-stock-last`. It appears in traces, tests, diffs and filter chips, so it is visible to storefronts and holds no secrets.
  
  - `slot` (id: "slot"): The higher rule pins a position this pin asks for, so this pin moves to the next free one.
    
    - `entity` (string · required): An entity named with its type, `type:id`, such as `product:SOFA-LUND-3`.
    
    - `position` (integer · required)
    
    - `by` (string · required): A rule's id, unique per release, such as `home/out-of-stock-last`. It appears in traces, tests, diffs and filter chips, so it is visible to storefronts and holds no secrets.
  
  - `placement` (id: "placement"): The higher rule places a banner at a grid position this placement asks for, so this one moves to the next free one.
    
    - `position` (integer · required)
    
    - `by` (string · required): A rule's id, unique per release, such as `home/out-of-stock-last`. It appears in traces, tests, diffs and filter chips, so it is visible to storefronts and holds no secrets.
  
  - `hidden` (id: "hidden"): The other rule hides the entity, and hide beats pin, whichever rule is higher.
    
    - `entity` (string · required): An entity named with its type, `type:id`, such as `product:SOFA-LUND-3`.
    
    - `by` (string · required): A rule's id, unique per release, such as `home/out-of-stock-last`. It appears in traces, tests, diffs and filter chips, so it is visible to storefronts and holds no secrets.
  
  - `strength` (id: "strength"): The higher rule boosts or buries the same target, and its strength counts. `target` is the target as a trace says it, such as `brand is "bosch"`.
    
    - `target` (string · required)
    
    - `by` (string · required): A rule's id, unique per release, such as `home/out-of-stock-last`. It appears in traces, tests, diffs and filter chips, so it is visible to storefronts and holds no secrets.
  
  - `sections` (id: "sections"): The higher rule sets the order of the sections.
    
    - `by` (string · required): A rule's id, unique per release, such as `home/out-of-stock-last`. It appears in traces, tests, diffs and filter chips, so it is visible to storefronts and holds no secrets.

- `entities` ([array of NamedEntity](#NamedEntity)): The entities it names, with what the catalog says of each, so an editor shows a pinned product or a banner's page by its title and photo. One the catalog no longer holds is marked `gone`: its effects do nothing, and the rule stays as the merchant wrote it.

- `fields` ([RuleFields](#RuleFields)): What an editor sets with fields, when the fields express the whole rule.

- `grid` (string): The category page whose grid this rule is, which that page arranges: the highest rule that is enabled, acts on that page alone in every channel and at every time, only while nothing is typed, and does nothing but pin within the first `GRID_SIZE` positions. Left out for every other rule, a lower one of the same shape included.

- `source` ([Rule](#Rule)): The rule as `rules.json` writes it, read only: left out where `fields` hold the whole rule. The management API changes such a rule through the draft's files.

## `ListedSynonym`

One entry with what a merchant wants to know of it.

- `group` (kind: "group"): Words that mean the same, each way round, such as `["couch", "sofa"]`. A word or phrase is in one group at most.
  
  - `words` (array of strings · required)

- `one_way` (kind: "one_way"): A word that also finds others, but not the other way round: `läufer` finds `teppich`. A word starts one such entry at most.
  
  - `from` (string · required)
  
  - `to` (array of strings · required)

- `never` (kind: "never"): Words that look alike but must never be merged, such as `["sessel", "sofa"]`. They change no search; an entry that would merge them is refused unless the write says `despite_never`.
  
  - `words` (array of strings · required)

## `NamedEntity`

An entity a rule names, as the catalog holds it in the list's channel and locale.

- `entity` (string · required): An entity named with its type, `type:id`, such as `product:SOFA-LUND-3`.

- `title` (string): Its title; left out where the catalog holds none, or no longer holds the entity.

- `image` (string): Its first photo's URL, as the catalog gives it; left out where there is none.

- `gone` (boolean): The catalog no longer holds it, or does not sell it in the channel.

## `PageLinks`

The pages around this one, as URLs to fetch.

- `first` (string · required)

- `last` (string · required)

- `prev` (string): Left out on the first page.

- `next` (string): Left out on the last page.

## `PageMeta`

Where this page stands in the whole list.

- `current_page` (integer · required)

- `last_page` (integer · required)

- `per_page` (integer · required)

- `total` (integer · required)

## `Pin`

- `entity` (string · required): An entity named with its type, `type:id`, such as `product:SOFA-LUND-3`.

- `position` (integer · required): The slot, counted from 1. Positions are unique within a rule; on a tie between rules the higher one takes the slot and the other moves to the next free one.

- `sponsored` (object): A paid placement: the hit names its campaign, so a storefront marks it as an ad and reports its views and clicks for the campaign. It is placed as any pin is, only where the product meets the page's category and filters.
  
  The campaign a paid placement belongs to: `{ "campaign": "Michelin spring" }`.
  
  - `campaign` (string · required): The merchant's name for it, which the campaign report counts by.

## `QueryInsight`

- `query` (string · required): The query's words as the engine reads them, such as `sofa grau`.

- `searches` (integer · required)

- `no_results` (integer · required): Of `searches`.

- `clicked` (integer · required): Of `searches`, those with a click.

- `with_results` (integer · required): Of `searches`, those with results.

- `no_click` (integer · required): Of `with_results`, those without a click.

- `average_position` (number): Where its clicked hits of the listed section stood, on average, counted from 1 across the pages; left out without such a click.

- `page_views` (integer · required): The page views that searched it, summed over the days.

- `results` (integer · required): What its latest search listed.

## `RefusedSynonym`

An entry that was not written, and why.

- `index` (integer · required): Its place among the entries sent, counted from 0.

- `entry` (object · required): The entry as it would have been written: trimmed, lowercased and each word once.
  
  One entry of a language's synonyms.
  
  - `group` (kind: "group"): Words that mean the same, each way round, such as `["couch", "sofa"]`. A word or phrase is in one group at most.
    
    - `words` (array of strings · required)
  
  - `one_way` (kind: "one_way"): A word that also finds others, but not the other way round: `läufer` finds `teppich`. A word starts one such entry at most.
    
    - `from` (string · required)
    
    - `to` (array of strings · required)
  
  - `never` (kind: "never"): Words that look alike but must never be merged, such as `["sessel", "sofa"]`. They change no search; an entry that would merge them is refused unless the write says `despite_never`.
    
    - `words` (array of strings · required)

- `conflicts` (array of objects · required): A clash as data and as one sentence, such as "“sofa” is in the group couch, sofa, settee already."
  
  - `too_few` (id: "too_few"): It names fewer than two different words; a one-way entry names a word and at least one other it finds.
  
  - `taken` (id: "taken"): The word is in another group already, or starts another one-way entry: `entry` is the one to add to instead, with its words.
    
    - `word` (string · required)
    
    - `entry` (string · required): A synonym entry's place in `synonyms.json`: its language, its kind and its index there, such as `de/groups/0`, `de/one_way/2` or `de/never/0`. A delete moves the entries after it up, so a write names the draft version it read.
    
    - `words` (array of strings · required)
  
  - `never` (id: "never"): It merges two words the `never` entry `entry` keeps apart; for a `never` entry, `entry` is the one that merges them.
    
    - `words` (array of strings · required)
    
    - `entry` (string · required): A synonym entry's place in `synonyms.json`: its language, its kind and its index there, such as `de/groups/0`, `de/one_way/2` or `de/never/0`. A delete moves the entries after it up, so a write names the draft version it read.

## `Rejection`

A row of the feed, or one value in a row, that was left out, and why.

- `row` (integer · required): The row as the merchant finds it in their file, counted from 1: the line of JSON Lines or delimited text (the header is row 1), the row of a sheet, the item of an XML feed. An entity made of several rows is named by its first.

- `id` (string): The entity's id, when the row names one.

- `column` (string): The export's column that holds what is wrong, as the header names it; left out for JSON Lines and for the row as a whole.

- `pointer` (string · required): A JSON pointer to the field within the entity the row became, such as `/variants/0/price`; empty for the row as a whole.

- `code` (string · required): What is wrong, as a code the panel translates.
  
  - `unreadable_feed`: The file cannot be read as the kind it seems to be, such as an XML feed that breaks off; nothing after the place it names was read.
  
  - `not_utf8`: The row is not UTF-8 text.
  
  - `not_json`: The row is not valid JSON.
  
  - `not_an_entity`: The row is JSON, but not one entity as an object.
  
  - `unknown_field`: The row has a field no entity, variant or offer has.
  
  - `invalid_field`: A field's value has the wrong shape, such as a price written as text.
  
  - `unknown_type`: The row's type is not a type of the release.
  
  - `field_not_of_type`: The row sets a field its type does not have, such as variants on a category.
  
  - `misplaced_offer`: Offer fields sit on a product that has variants, or both on an entity and in its offers.
  
  - `unknown_channel`: An offer names a channel the release does not have, or offer fields need a channel to be named.
  
  - `wrong_currency`: An offer's currency is not its channel's.
  
  - `duplicate_offer`: Two offers of one entity or variant name the same channel.
  
  - `duplicate_variant`: Two variants of one product have the same id.
  
  - `duplicate_id`: An earlier row has the same type and id.
  
  - `missing_id`: The row has no id: the column that `id` maps is empty, or nothing maps it.
  
  - `wrong_value`: A value is not one of the attribute's type, such as a list where the attribute takes one value.
  
  - `not_a_number`: A number or quantity cannot be read, such as "about two metres".
  
  - `wrong_unit`: A quantity's unit measures something else than the attribute, such as kilograms for a width.

- `message` (string · required): What is wrong, as a sentence.

- `value` (string): The value that is wrong, as the file writes it, such as "ab 249 €"; left out when the row as a whole is.

## `RejectionGroup`

Rejections with one cause: the same code, and in a mapped export the same column.

- `code` (string · required): What is wrong with a rejected row or value. Codes are stable; the sentence beside them may change.
  
  - `unreadable_feed`: The file cannot be read as the kind it seems to be, such as an XML feed that breaks off; nothing after the place it names was read.
  
  - `not_utf8`: The row is not UTF-8 text.
  
  - `not_json`: The row is not valid JSON.
  
  - `not_an_entity`: The row is JSON, but not one entity as an object.
  
  - `unknown_field`: The row has a field no entity, variant or offer has.
  
  - `invalid_field`: A field's value has the wrong shape, such as a price written as text.
  
  - `unknown_type`: The row's type is not a type of the release.
  
  - `field_not_of_type`: The row sets a field its type does not have, such as variants on a category.
  
  - `misplaced_offer`: Offer fields sit on a product that has variants, or both on an entity and in its offers.
  
  - `unknown_channel`: An offer names a channel the release does not have, or offer fields need a channel to be named.
  
  - `wrong_currency`: An offer's currency is not its channel's.
  
  - `duplicate_offer`: Two offers of one entity or variant name the same channel.
  
  - `duplicate_variant`: Two variants of one product have the same id.
  
  - `duplicate_id`: An earlier row has the same type and id.
  
  - `missing_id`: The row has no id: the column that `id` maps is empty, or nothing maps it.
  
  - `wrong_value`: A value is not one of the attribute's type, such as a list where the attribute takes one value.
  
  - `not_a_number`: A number or quantity cannot be read, such as "about two metres".
  
  - `wrong_unit`: A quantity's unit measures something else than the attribute, such as kilograms for a width.

- `column` (string): The export's column, when the cause sits in one.

- `count` (integer · required): How many rows, or values, it left out.

- `examples` ([array of Rejection](#Rejection) · required): The first of them, up to `LISTED_EXAMPLES`.

## `ResolvedCondition`

What the query named: its category, its detected filters, and whether any text is left.

- `category` (object): A category, exactly or including everything below it.
  
  - `is` (string or array of strings): One value, or a list meaning any of them.
  
  - `within` (string or array of strings): One value, or a list meaning any of them.

- `filters` ([object](/docs/reference/query-api#Selector)): The detected filters, as a selector over the detected values.

- `complete` (boolean): True when the query resolved completely and no text is left.

## `Rule`

- `id` (string · required): A rule's id, unique per release, such as `home/out-of-stock-last`. It appears in traces, tests, diffs and filter chips, so it is visible to storefronts and holds no secrets.

- `description` (string · required): One line, up to 200 characters, shown in the panel, the trace and diffs.

- `enabled` (boolean): A disabled rule is not evaluated. Default: `true`.

- `when` ([Condition](#Condition)): The condition over the request. Without one, the rule always matches.

- `then` ([Effects](#Effects) · required): What the rule does: at least one effect.

- `schedule` (object): When the rule is active, checked against the time in the request, never the engine's clock.
  
  A window in time: from `from` (inclusive) until `until` (exclusive). Either end may be open.
  
  - `from` (string): A point in time as RFC 3339 with an offset, such as `2026-11-27T00:00:00+01:00`.
  
  - `until` (string): A point in time as RFC 3339 with an offset, such as `2026-11-27T00:00:00+01:00`.

- `origin` (object): Where the rule came from. Without it, the merchant made it.
  
  Where an imported rule or overlay came from.
  
  - `import` (string · required): What it was imported from, such as the previous search's export.
  
  - `ref` (string · required)

## `RuleFields`

The fields of a rule an editor sets.

- `when` (object · required): When a rule applies.
  
  - `trigger` (object · required): What sets a rule off.
    
    - `always` (kind: "always"): Every search and category page.
    
    - `query` (kind: "query"): Searches whose words are one of the phrases, or contain one. Matching is literal after normalization: no typos, synonyms or plurals.
      
      - `matching` (string · required): - `is`: The query is exactly the phrase.
        
        - `contains`: The query contains the phrase as a run of whole words.
      
      - `phrases` (array of strings · required)
    
    - `category` (kind: "category"): A category page.
      
      - `category` (string · required): The id of a category node, such as `wohnen/sofas`: the merchant's id of a `category` entity.
      
      - `below` (boolean): The pages below it too. Default: only this page.
      
      - `without_words` (boolean): Only while no words are typed on the page, as a grid of its top positions is.
  
  - `channel` (string): Only in this channel. Left out for every channel.

- `then` ([ThenFields](#ThenFields) · required): What a rule does. At least one effect.

- `window` (object): When the rule is active, checked against the time in the request. Left out for a rule without a window.
  
  A window in time: from `from` (inclusive) until `until` (exclusive). Either end may be open.
  
  - `from` (string): A point in time as RFC 3339 with an offset, such as `2026-11-27T00:00:00+01:00`.
  
  - `until` (string): A point in time as RFC 3339 with an offset, such as `2026-11-27T00:00:00+01:00`.

## `RuleList`

The rules of a release in precedence order: the first rule is the highest.

- `release` (string · required): The configuration that answered: the live release, or the draft the files make.

- `snapshot` (string · required): The catalog the products were looked up in.

- `channel` (string · required): A channel's id, such as `de` or `ch`: a market or storefront.

- `locale` (string · required): A BCP 47 language tag such as `de`, `de-CH` or `en`. A locale falls back along its tag: `de-CH` to `de`.

- `time` (string · required): The time the states are as at.

- `rules` ([array of ListedRule](#ListedRule) · required)

## `RunProgress`

How far an index run got, written by the indexer while it works, so a merchant watches it go through. A failed run keeps the last it wrote, so its report says the step it failed in.

- `stage` (string · required): What a running index run does now, in the order it does it.
  
  - `reading`: Learning the file: its columns, its mapping and where each product ends.
  
  - `checking`: Mapping every row and reading its values against the release; counts `entities`.
  
  - `indexing`: Compiling the entities and writing them to new indexes beside the live ones; counts `compiled` and `indexed`.
  
  - `going_live`: Swapping the new indexes in for the live ones.

- `entities` (integer · required): Entities read and checked so far; from `indexing` on, all the run indexes.

- `compiled` (integer · required): Entities compiled and handed to the engine so far.

- `indexed` (integer · required): Documents the engine has indexed so far.

## `RunReport`

What an index run did with its snapshot: how much it indexed, and every row it left out and why.

- `rows` (integer · required): Rows read from the feed, blank lines not counted.

- `feed` ([FeedReport](#FeedReport)): How the export was read and mapped; left out for OrbSearch's own JSON Lines, which need no mapping.

- `entities` (integer · required): Entities indexed.

- `documents` (integer · required): Engine documents written, over every index.

- `indexes` (array of strings · required): The engine indexes the run made live, one per entity type and locale, such as `product-de`.

- `rejected` (integer · required): Rows left out because something in them is wrong; the rest of the feed was indexed.

- `rejections` ([array of RejectionGroup](#RejectionGroup)): The rejected rows grouped by what is wrong, the most common first, each with its first rows as examples.

- `values` ([ValuesReport](#ValuesReport)): What the import made of the attribute values: those it left out, and those whose meaning it derived.

- `defaults` ([Defaults](#Defaults)): The release files the release leaves out, derived from this run's catalog, each setting with its reason. The Query API reads them with the release while the run is live.

- `refresh_at` (string): The next moment a sale window opens or closes, or an overlay ends. The indexes hold the prices and corrections of the run's time, so the indexer builds the same snapshot and release again then.

- `course` ([Course](#Course)): How the run took its release live and why; left out for a run that failed or has not gone live yet. A run that switched or only wrote settings carries the counts of the live run it followed, since its catalog is the same.

- `offers` ([AppliedOffers](#AppliedOffers)): The offer changes the run's indexes hold: those received since its snapshot first arrived, applied on top of it when the run built its indexes, and every batch the indexer wrote into them while the run was live. Left out when they hold none. A run that switched or only wrote settings carries the live run's, since its indexes are the same.

## `SearchSettings`

How every type of the release is searched.

- `release` (string · required): The configuration that decided: the live release, or the draft the files make.

- `snapshot` (string · required): The catalog the derived settings come from.

- `locale` (string · required): A BCP 47 language tag such as `de`, `de-CH` or `en`. A locale falls back along its tag: `de-CH` to `de`.

- `types` ([array of TypeSearch](#TypeSearch) · required): In the order of `types.json`.

## `Shift`

A boost or bury.

- `entity` (string): An entity named with its type, `type:id`, such as `product:SOFA-LUND-3`.

- `entities` (array of strings)

- `where` ([object](/docs/reference/query-api#Selector)): Picks entities (`where`). Attribute codes and the built-in fields `brand`, `price`, `on_sale`, `availability` and `delivery_days` are keys of the same object; `category` takes `is` or `within`.
  
  `{ "any": [{ "brand": "bosch" }, { "quality": "oe" }], "not": { "availability": "out_of_stock" } }`

- `type` (string): With `where`: only entities of this type.

- `strength` (string · required): One of `slight`, `medium` or `strong`.

## `ShownFacet`

A facet and how it is shown.

- `field` (string · required): An attribute code, or one of `category`, `brand`, `price`, `on_sale`, `availability` and `delivery_days`, which reads the latest day of delivery.

- `kind` (string): How the facet is shown. Default: the field's natural kind, such as a list for options and a range for numbers.
  
  - `list`
  
  - `swatch`
  
  - `hierarchical`
  
  - `range`
  
  - `buckets`
  
  - `toggle`
  
  - `relative`: Dates relative to the request's time, such as "new in the last 30 days". Bucket bounds are days.

- `buckets` ([array of Bucket](#Bucket)): The bounds of `buckets` and `relative` facets, in ascending order.

- `show` (string): Options: show the values, or the groups they belong to.
  
  - `values`: Options: show the values, or the groups they belong to.
  
  - `groups`: Options: show the values, or the groups they belong to.

- `order` (string): The order of a facet's values. Default: most results first; buckets keep their own order; grades, buttons and a select keep the order the values are listed in.
  
  - `count`: Most results first.
  
  - `value_order`: The order of the attribute's values.
  
  - `label`: Alphabetical by label.

- `single` (boolean): One value at most, chosen from a radio group with "Any" first, such as a delivery time whose buckets overlap.

- `description` (string or map of strings): Text shown under the facet's name and read with it, such as what a delivery time counts from. Never a tooltip.

- `headings` (array of objects): Parts of the list under headings of their own, such as "Wood" above oak and walnut, in order. Values no heading names follow the last one.
  
  A heading inside a facet and the values it stands above.
  
  - `label` (string or map of strings · required): A plain value, or a map from locale to value such as \{ "de": "Farbe", "en": "Color" \}.
  
  - `values` (array of strings · required): Value codes, or group codes where the facet shows groups, in display order.

- `search` (boolean): A search box above the values, for long lists such as brands.

- `limit` (integer · at least 1): The most values a list or swatch carries with the page before `more` says there are others: the most frequent ones, and every chosen one. Default: the limit [`facet_values`](/docs/reference/limits#facet_values). A select or a scale that shows every value raises it.

- `display` (string): How the values look beyond their kind. Default: the kind's own look; a rating shows stars.
  
  - `slider`: A range: a two-thumb slider above the two inputs, which stay.
  
  - `histogram`: A range over the price: a slider with the distribution of the prices drawn behind it, in the bins of a fixed ladder of preferred numbers (`histogram` of the response). Prices that fall in a single bin get the plain slider.
  
  - `stars`: A rating: stars beside each bucket; its words carry the meaning.
  
  - `grades`: An option's values on badges in their own swatch colors, such as the energy label's A to G, in the order the values are listed. Every listed value needs a swatch.
  
  - `buttons`: Values or buckets as a wrap of toggle buttons, such as sizes.
  
  - `select`: One value at most, chosen from one native select with "Any" first, for a long ordered list such as a tyre width.
  
  - `images`: Each value's image beside its name: a brand's logo, or the image an option's value carries, such as an icon.

- `custom_display` (string): A storefront display of the shop's own, by the name the shop registered it under, such as `color_tiles`. A storefront without it draws `display`, or the kind's own look, so `display` keeps what it means for the data.

## `Snapshot`

A catalog as it was uploaded, named by its content.

- `id` (string · required): The id of a catalog snapshot. A snapshot is named by its content and never changes.

- `bytes` (integer · required)

- `uploaded_at` (string · required): The last time these bytes were sent. A publish or rebuild indexes the current catalog: the snapshot uploaded last that is kept and that the indexer did not reject.

- `removed_at` (string): When the indexer's clean-up removed its file because nothing needed it any more; its runs stay. Sending the same bytes again brings it back.

## `SortOption`

An order a page offers.

- `code` (string · required): What a request's `sort` names to choose it; `relevance` is built in.

- `label` (string · required): In the request's locale.

- `default` (boolean): The page starts in this order while the shopper chooses none: the sort its category or the layout's default sets, or relevance where the request has words, which rank by it.

## `StoredRelease`

A release as the control plane stores it, with when it was published. Storing does not publish it.

- `id` (string · required): The id of a release. A release is named by its content and never changes.

- `created_at` (string · required): A point in time as RFC 3339 with an offset, such as `2026-11-27T00:00:00+01:00`.

- `published_at` (string): When it was last published; the release published last is the one index runs compile.

- `files` (map of strings): On a single release: its files by name, in the canonical form the Query API wrote.

- `role` (string): Where it stands among the releases index runs took live; left out for any other release, so the panel needs to work nothing out.
  
  - `live`: Searches read it now.
  
  - `previous`: The release the live one replaced, which publishing it again, a rollback, brings back.
  
  - `going_live`: It is published and an index run is queued or running; it is not live yet.

- `course` ([Course](#Course)): How the latest run that took it live did so; left out for a release that never went live.

## `SynonymList`

Every language's synonyms.

- `locales` (array of strings · required): The languages the channels serve, in channel order: the first is the shop's, and a shop with one needs no choice of language.

- `reads` (map of strings · required): For each locale the channels serve, the dictionary it reads: its own, else the one of the nearest shorter tag, such as `de` for `de-CH`. A locale with no dictionary along its tag reads one under its own name once it has entries. A client opens the dictionary a shopper's locale reads from here, never by matching tags itself.

- `dictionaries` ([array of ListedDictionary](#ListedDictionary) · required): One dictionary per language the channels serve, then those for a language none serves yet.

## `ThenFields`

What a rule does. At least one effect.

- `pin` ([array of Pin](#Pin)): Chosen entities at fixed positions, counted from 1.

- `hide` (array of objects): Takes entities out of the results. Hide beats pin.
  
  What an effect is about.
  
  - `entities` (of: "entities"): Chosen products or other entities.
    
    - `entities` (array of strings · required)
  
  - `brand` (of: "brand"): Everything of a brand, as the brand facet counts it.
    
    - `brand` (string · required)
  
  - `category` (of: "category"): Everything in a category.
    
    - `category` (string · required): The id of a category node, such as `wohnen/sofas`: the merchant's id of a `category` entity.
    
    - `below` (boolean): The categories below it too. Default: only this one.

- `boost` (array of objects): Moves entities up, within relevance.
  
  A boost or bury with its named strength.
  
  - `subject` (object · required): What an effect is about.
    
    - `entities` (of: "entities"): Chosen products or other entities.
      
      - `entities` (array of strings · required)
    
    - `brand` (of: "brand"): Everything of a brand, as the brand facet counts it.
      
      - `brand` (string · required)
    
    - `category` (of: "category"): Everything in a category.
      
      - `category` (string · required): The id of a category node, such as `wohnen/sofas`: the merchant's id of a `category` entity.
      
      - `below` (boolean): The categories below it too. Default: only this one.
  
  - `strength` (string · required): One of `slight`, `medium` or `strong`.

- `bury` (array of objects): Moves entities down, within relevance.
  
  A boost or bury with its named strength.
  
  - `subject` (object · required): What an effect is about.
    
    - `entities` (of: "entities"): Chosen products or other entities.
      
      - `entities` (array of strings · required)
    
    - `brand` (of: "brand"): Everything of a brand, as the brand facet counts it.
      
      - `brand` (string · required)
    
    - `category` (of: "category"): Everything in a category.
      
      - `category` (string · required): The id of a category node, such as `wohnen/sofas`: the merchant's id of a `category` entity.
      
      - `below` (boolean): The categories below it too. Default: only this one.
  
  - `strength` (string · required): One of `slight`, `medium` or `strong`.

- `redirect` (object): Sends the shopper elsewhere.
  
  Where a redirect sends the shopper.
  
  - `page` (to: "page"): A page of the shop: a category, a brand, a product or another entity. Its address follows the catalog.
    
    - `page` (string · required): An entity named with its type, `type:id`, such as `product:SOFA-LUND-3`.
  
  - `url` (to: "url"): A fixed URL: a path such as `/werkstatt`, or one that starts with `https://`.
    
    - `url` (string · required)

- `place` ([array of BannerPlacement](#BannerPlacement)): Banners and teasers above, among or below the results, each with its words in every locale the release serves.

## `TypeSearch`

How one type is searched.

- `type` (string · required): The code of an entity type, such as `product`, `category` or a merchant's own `store`.

- `label` (string · required): The type's name in the locale.

- `fields` (object · required): The fields a type searches, in priority order: a word found in an earlier field ranks a hit higher.
  
  - `source` (string · required): Where a search setting comes from.
    
    - `set`: The merchant set it, in the release's or the draft's `types.json`.
    
    - `derived`: The release leaves it out, so the index run derived it from the catalog: the import's default.
    
    - `built_in`: Nothing sets it: OrbSearch's own default.
  
  - `fields` (array of objects · required): A field a type can search.
    
    - `field` (string · required): As `types.json` names it, such as `title` or `attributes.mpn`.
    
    - `label` (string · required): Its name in the locale.

- `addable` (array of objects · required): The fields it could search beside those: the built-in text fields, then every text, identifier and option attribute, in the order of `attributes.json`.
  
  A field a type can search.
  
  - `field` (string · required): As `types.json` names it, such as `title` or `attributes.mpn`.
  
  - `label` (string · required): Its name in the locale.

- `typos` ([TypoSettings](#TypoSettings) · required): Whether and from how many letters on a type's words find with a typo.

- `exempt` ([ExemptAttributes](#ExemptAttributes) · required): The attributes a type's words find only as written or by their start.

## `TypoSettings`

Whether and from how many letters on a type's words find with a typo.

- `source` (string · required): Set, or built in; never derived.
  
  - `set`: The merchant set it, in the release's or the draft's `types.json`.
  
  - `derived`: The release leaves it out, so the index run derived it from the catalog: the import's default.
  
  - `built_in`: Nothing sets it: OrbSearch's own default.

- `enabled` (boolean · required)

- `one_typo` (integer · required): The fewest letters a word needs to find with one typo.

- `two_typos` (integer · required): The fewest letters a word needs to find with two typos.

## `UnstoredSlug`

A listed value or group whose slug the run made from its label, because attributes.json stores none.

- `attribute` (string · required): The code of an attribute definition, such as `color` or `seat_height`. The reserved words `any`, `all`, `not`, `category`, `brand`, `price`, `on_sale`, `availability`, `delivery_days` and `rating` cannot be attribute codes.

- `value` (string · required): The value's or group's code.

- `slug` (string or map of strings · required): A plain value, or a map from locale to value such as \{ "de": "Farbe", "en": "Color" \}.

## `ValuesReport`

What the import made of the feed's attribute values beyond reading them as their definitions say.

- `rejected` (integer): Values left out because they do not fit their attribute; their entity was indexed without them.

- `rejections` ([array of RejectionGroup](#RejectionGroup)): The values left out grouped by what is wrong, the most common first, each with its first values as examples.

- `new` (integer): Option values attributes.json does not list; each became a value of its own.

- `ungrouped` (integer): Values of attributes with color groups that no stage of the built-in colors could place in a group.

- `derived` ([array of DerivedValue](#DerivedValue)): The values whose meaning the import derived, the most common first.

- `unstored` (integer): Values and groups attributes.json lists without a slug in a locale: the run made it from the label, so a new label would move the URLs that hold it. A write through the management API stores it.

- `unstored_slugs` ([array of UnstoredSlug](#UnstoredSlug)): The first of them, in the order of attributes.json, with the slugs the run made.

## `Weight`

A boost or bury that weighed a hit.

- `rule` (string · required): A rule's id, unique per release, such as `home/out-of-stock-last`. It appears in traces, tests, diffs and filter chips, so it is visible to storefronts and holds no secrets.

- `effect` (string · required): One of `resolve`, `rewrite`, `redirect`, `filter`, `hide`, `pin`, `boost`, `bury`, `sections` or `place`.

- `factor` (number · required)
