# Channels

Set up the markets a shop sells in, each with its languages, currency, countries and the products it carries.

A [channel](/docs/reference/glossary#channel) is a market: the [locales](/docs/reference/glossary#locale) its pages speak, the currency its prices are in and the countries it serves. The home store sells in one channel, `de`, in German and English:

```json title="tests/fixtures/home/channels.json (trimmed)"
{
    "channels": [
        {
            "id": "de",
            "label": { "de": "Deutschland", "en": "Germany" },
            "locales": ["de", "en"],
            "currency": "EUR",
            "countries": ["DE"]
        }
    ]
}
```

Labels, URLs and slugs exist per locale, prices per channel. `countries` guards privacy: the search log masks a phone number a shopper types into search, read as written there, before it keeps the query.

A release without `channels.json` derives it from the catalog: the locales its texts are keyed by or written in, the channels its offers name, and the currency their prices write. Changing `channels.json` rebuilds the indexes.

**Reference:** [`channels.json`](/docs/reference/release-files/channels) · [`locales`](/docs/reference/release-files/channels#locales) · [`currency`](/docs/reference/release-files/channels#currency)

## The channel and locale a request gets

A request without `channel` is answered in the first channel, and without `locale` in that channel's first locale. The trace says which it got:

```sh title="Terminal"
curl -s 'http://127.0.0.1:7800/v1/search?query=sofa&debug=1' | jq -c '.trace.request | {channel, locale}'
```

```json title="Answer: 200 · 4.9 ms · release b25a6aaa"
{"channel":"de","locale":"de"}
```

A locale the channel does not serve is refused, and the answer names the ones it does:

```sh title="Terminal"
curl -s 'http://127.0.0.1:7800/v1/search?query=sofa&locale=fr' | jq -r '.violations[].message'
```

```text title="Answer: 400 · 1.4 ms"
The channel de serves de and en, not fr.
```

[Channel, locale and context](/docs/search#channel-locale-and-context) shows the same search in English.

**Reference:** [`channel`](/docs/reference/query-api#search.channel) · [`locale`](/docs/reference/query-api#search.locale)

## Prices in the channel's currency

Every offer is in its channel's currency. An offer without `currency` takes the channel's, and a catalog line whose offer names another currency is left out and reported, since the shopper would see a wrong price.

Offer fields written on a variant, such as `"price": 749.0`, are its offer in the only channel. A shop with several channels gives each variant one offer per channel instead:

```json title="catalog.jsonl, one variant (trimmed)"
{ "id": "SOFA-ASKA-2-GRAU", "offers": [{ "channel": "de", "price": 749.0, "availability": "in_stock" }] }
```

**Reference:** [`offers`](/docs/reference/catalog/entity#variants.offers) · [`currency`](/docs/reference/catalog/entity#variants.offers.currency)

## What a channel sells

An `assortment` is a selector for the products a channel sells. This one leaves out the lamps by Lumivo, such as the pendant lamp `LEUCHTE-KUGEL`:

```json title="channels.json"
{
    "channels": [
        { "id": "de", "locales": ["de", "en"], "currency": "EUR", "assortment": { "not": { "brand": "Lumivo" } } }
    ]
}
```

The [index run](/docs/reference/glossary#index-run) applies it to every variant. A variant it leaves out has no offer in the channel, so searches, facet counts, suggestions and the product page all leave it out, and no request can bring it back. The selector reads attributes, the brand and the offer fields of its own channel, never a relation.

[`POST $api/preview/find`](/docs/reference/management-api#preview-find) names the assortment when it is why a product is missing.

**Reference:** [`assortment`](/docs/reference/release-files/channels#assortment)

## Context for rules

`context` declares the keys a request may carry, with the values each allows, so business customers can get rules of their own:

```json title="channels.json"
{
    "channels": [{ "id": "de", "locales": ["de", "en"], "currency": "EUR" }],
    "context": { "customer_group": ["b2c", "b2b"] }
}
```

A request then sends `"context": { "customer_group": "b2b" }`, and a rule's `when.context` matches it ([Rules](/docs/rules)). A rule that names an undeclared key fails validation, and a request that sends one is refused with a `400`. Context never carries personal data. The home store declares none.

**Reference:** [`context`](/docs/reference/release-files/channels#context) · [`when.context`](/docs/reference/release-files/rules#when.context)

## Next

- [Search and browse](/docs/search): send the channel, locale and context with a request.
- [Types and attributes](/docs/types-and-attributes): the labels each locale shows.
- [Live prices and stock](/docs/prices-and-stock): change an offer in a channel between two catalogs.
