# Produkte

> Listen, suchen, lesen und erstellen oder aktualisieren Sie Produkte mit Listenpreisen oder jedem Kundenpreis.

Ein Produkt hat eine SKU, einen Listenpreis und optionale Marke, Kategorie, Lagerstatus und zusätzliche Details. Preise werden immer für Sie berechnet: siehe [Preise](/docs/api/prices).

Produkte können auch `familyId` und `orderStep` (Standard 1) haben. Ein einzelnes Produkt enthält optionale `family`-Metadaten mit Namen, Variantenattribute und Voreinstellungen. Ein konfigurierter Preis enthält `orderingFields`, `configurationRequired`, `definitionVersion` und optional kundenspezifische `quantityBreaks`. Bestellfelder sind Eingaben des Käufers; `details` bleiben Produktfakten.

**POST** `/api/v1/products/{id}/quote`

Diese schreibgeschützte Operation akzeptiert `{ "customer": "ACME01", "qty": 3, "configuration": { "length": 2.75, "reference": "Kitchen" } }`. `customer` ist für die Staff-Listenpreisberechnung optional. Schreibgeschützte Schlüssel können es verwenden. Sie gibt `data.productId`, `qty`, validierte `fields`, `definitionVersion` und `price` mit `unit`, `line` und der gewählten Spezifikation zurück. Fehlende erforderliche Felder führen zur Konfiguration für den Preis; ungültige Kombinationen werden abgelehnt. Es wird kein Warenkorb, Auftrag oder Zahlung erstellt. Verwenden Sie `price.line` anstelle der Multiplikation des Einzelpreises.

Imports akzeptieren optionale `family`, `orderStep` und `orderingDefinition`. Eine Definition verwendet das Schema in OpenAPI, erfordert Pro und globale Preisberechtigung und gibt `ruleDrafts` zur Überprüfung über den bestehenden Preisänderungsworkflow zurück. Fehlende Struktur belässt bestehende Einstellungen unverändert. Siehe [trade catalogue setup](/docs/guides/trade-catalogues).

## Das Produktobjekt

```json
{
  "id": "3f8a2c1e-9b4d-4e6f-a7c8-1d2e3f4a5b6c",
  "sku": "HX-8510",
  "name": "Hex bolt M10 x 50 zinc",
  "description": "Grade 8.8, zinc plated, fully threaded.",
  "brandId": "a1b2c3d4-0000-4000-8000-000000000001",
  "categoryId": "a1b2c3d4-0000-4000-8000-000000000002",
  "manufacturerRef": "DIN933-M10-50",
  "unitLabel": "Box of 100",
  "minOrderQty": 1,
  "availability": "in_stock",
  "stockQty": 240,
  "lowStockAt": null,
  "leadTimeNote": null,
  "dealText": null,
  "active": true,
  "visibility": "all",
  "details": { "Finish": "Zinc", "Thread": "M10" },
  "createdAt": "2026-08-14T09:30:00.000Z",
  "updatedAt": "2026-09-20T16:02:11.000Z",
  "price": {
    "unit": 1850,
    "line": 1850,
    "list": 1850,
    "discountBp": 0,
    "source": "list",
    "label": ""
  }
}
```

| Feld                    | Typ               | Beschreibung                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| ----------------------- | ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`                    | string            | Produkt-ID.                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `sku`                   | string            | Ihre Lagernummer. Eindeutig im Workspace, unabhängig von Groß-/Kleinschreibung.                                                                                                                                                                                                                                                                                                                                                                     |
| `name`                  | string            | Produktname.                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `description`           | string oder null  | Längere Beschreibung.                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `brandId`, `categoryId` | string oder null  | Siehe [Marken und Kategorien](#brands-and-categories).                                                                                                                                                                                                                                                                                                                                                                                              |
| `manufacturerRef`       | string oder null  | Herstellerartikelnummer. Suchbar wie die SKU.                                                                                                                                                                                                                                                                                                                                                                                                       |
| `unitLabel`             | string            | Was eine Einheit ist, z. B. „Stück“ oder „Karton mit 100“.                                                                                                                                                                                                                                                                                                                                                                                          |
| `minOrderQty`           | integer           | Kleinste Menge, die Käufer bestellen können.                                                                                                                                                                                                                                                                                                                                                                                                        |
| `availability`          | string            | `not_tracked`, `in_stock`, `low_stock`, `out_of_stock` oder `made_to_order`. Ein Label für Käufer: Jedes Produkt kann bestellt werden. Wenn Sie es ohne `stockQty` senden, löschen Sie den gespeicherten Zähler (Sie setzen den Status manuell). Mit `stockQty` berechnet es sich für Sie: 0 oder weniger ist `out_of_stock`, bis zum Mindestniveau ist `low_stock`, darüber ist `in_stock`. `made_to_order` wird niemals durch die Zahl verändert. |
| `stockQty`              | integer oder null | Einheiten auf Lager, oder `null`, wenn Sie dieses Produkt nicht zählen. Wenn festgelegt, folgt `availability` darauf. Wird ausgelassen, wenn Sie als Kunde abfragen (`customer`).                                                                                                                                                                                                                                                                   |
| `lowStockAt`            | integer oder null | Dieses Produkt’s eigenes Niedrigbestandsniveau, oder `null`, um das Workspace-Niveau zu verwenden. Wird ausgelassen, wenn Sie als Kunde abfragen.                                                                                                                                                                                                                                                                                                   |
| `leadTimeNote`          | string oder null  | Z. B. „3–5 Arbeitstage“.                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `dealText`              | string oder null  | Eine Notiz neben dem Preis, z. B. „min 12 btls 45“. Der Titel ist das Deal-Label des Workspaces (Einstellungen, Kataloganzeige).                                                                                                                                                                                                                                                                                                                    |
| `active`                | boolean           | Inaktive Produkte werden Käufern nicht angezeigt.                                                                                                                                                                                                                                                                                                                                                                                                   |
| `visibility`            | string            | `all`, oder `selected`, wenn nur ausgewählte Kunden es sehen können.                                                                                                                                                                                                                                                                                                                                                                                |
| `details`               | object            | Zusätzliche Spalten aus Importen, z. B. `{ "Finish": "Zinc" }`.                                                                                                                                                                                                                                                                                                                                                                                     |
| `price`                 | object oder null  | Der Preis bei Menge 1 (oder `qty`). Siehe [Preise](/docs/api/prices#the-price-object). `unit` ist `null`, wenn das Produkt noch keinen Preis hat.                                                                                                                                                                                                                                                                                                   |

Lagerbestände sind Ihre Aufgabe, um sie aktuell zu halten: Bestellungen ändern `stockQty` nie, senden Sie es also immer, wenn sich Ihr Lagerbestand ändert. Kunden sehen nur den `availability`-Status, nie die Zahl. Bei Null kann ein Produkt immer noch bestellt werden; es wird einfach als ausverkauft gekennzeichnet.

`GET /products/{id}` beinhaltet auch `brand` und `category`-Namen.

Bilder werden von der API nicht zurückgegeben. Sie können eines mit `imageUrl` beim Erstellen oder Aktualisieren festlegen.

## Produkte auflisten oder suchen

**GET** `/api/v1/products`

Ohne `q` werden Produkte nach Namen aufgelistet. Mit `q` kommen die Ergebnisse in dieser Reihenfolge:

1. exakte SKU oder Herstellerreferenz
2. SKU oder Herstellerreferenz, die mit `q` beginnt
3. Volltextsuche in Namen, Marke, Kategorie und Beschreibung (3 oder mehr Zeichen; kürzere Abfragen passen zum Anfang des Namens)

Geben Sie `customer` an, um jede Zeile für diesen Kunden zu bewerten und nur die Produkte zurückzugeben, die dieser Kunde sehen kann (aktiv und entweder für alle oder für ihn ausgewählt). Das ist genau das, was der Kunde in ihrem Handelsportal sieht.

| Name           | Typ                 | Erforderlich | Beschreibung                                                                                                                               |
| -------------- | ------------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `q`            | string              | nein         | SKU, Herstellerreferenz, Name, Marke oder Kategorie. Bis zu 200 Zeichen.                                                                   |
| `category`     | string              | nein         | Kategorie-ID.                                                                                                                              |
| `brand`        | string              | nein         | Marken-ID.                                                                                                                                 |
| `availability` | string              | nein         | Einer der Verfügbarkheitswerte.                                                                                                            |
| `active`       | `true` oder `false` | nein         | `true` gibt nur aktive Produkte zurück. Standardmäßig `true`, wenn `customer` gesetzt ist; andernfalls werden alle Produkte zurückgegeben. |
| `customer`     | string              | nein         | Kunden-ID oder Kontocod.                                                                                                                   |
| `limit`        | integer             | nein         | 1 bis 50. Standard 50.                                                                                                                     |
| `offset`       | integer             | nein         | Zeilen, die übersprungen werden. Standard 0.                                                                                               |

```bash
curl "https://tradecatalog.app/api/v1/products?q=hex%20bolt&customer=OAK01&limit=20" \
  -H "Authorization: Bearer $TRADECATALOG_API_KEY"
```

```js
const params = new URLSearchParams({
  q: 'hex bolt',
  customer: 'OAK01',
  limit: '20',
})
const res = await fetch(`https://tradecatalog.app/api/v1/products?${params}`, {
  headers: { Authorization: `Bearer ${process.env.TRADECATALOG_API_KEY}` },
})
const { data: products, nextOffset } = await res.json()
```

```json
{
  "data": [
    {
      "id": "3f8a2c1e-9b4d-4e6f-a7c8-1d2e3f4a5b6c",
      "sku": "HX-8510",
      "name": "Hex bolt M10 x 50 zinc",
      "description": "Grade 8.8, zinc plated, fully threaded.",
      "brandId": "a1b2c3d4-0000-4000-8000-000000000001",
      "categoryId": "a1b2c3d4-0000-4000-8000-000000000002",
      "manufacturerRef": "DIN933-M10-50",
      "unitLabel": "Box of 100",
      "minOrderQty": 1,
      "availability": "in_stock",
      "leadTimeNote": null,
      "active": true,
      "visibility": "all",
      "details": { "Finish": "Zinc", "Thread": "M10" },
      "createdAt": "2026-08-14T09:30:00.000Z",
      "updatedAt": "2026-09-20T16:02:11.000Z",
      "price": {
        "unit": 1573,
        "line": 1573,
        "list": 1850,
        "discountBp": 1500,
        "source": "brand",
        "label": "Brand discount −15%"
      }
    }
  ],
  "nextOffset": null,
  "currency": "GBP"
}
```

## Ein Produkt abrufen

**GET** `/api/v1/products/{id}`

| Name       | In    | Typ     | Erforderlich | Beschreibung                                                                                |
| ---------- | ----- | ------- | ------------ | ------------------------------------------------------------------------------------------- |
| `id`       | path  | string  | ja           | Produkt-ID.                                                                                 |
| `customer` | query | string  | nein         | Kunden-ID oder Kontocod. Gibt `404` zurück, wenn dieser Kunde das Produkt nicht sehen kann. |
| `qty`      | query | integer | nein         | Menge zum Preis, 1 bis 1.000.000. Standard 1. `price.line` ist `unit × qty`.                |

```bash
curl "https://tradecatalog.app/api/v1/products/3f8a2c1e-9b4d-4e6f-a7c8-1d2e3f4a5b6c?customer=OAK01&qty=5" \
  -H "Authorization: Bearer $TRADECATALOG_API_KEY"
```

```js
const res = await fetch(
  `https://tradecatalog.app/api/v1/products/${productId}?customer=OAK01&qty=5`,
  { headers: { Authorization: `Bearer ${process.env.TRADECATALOG_API_KEY}` } },
)
const { data: product } = await res.json()
```

```json
{
  "data": {
    "id": "3f8a2c1e-9b4d-4e6f-a7c8-1d2e3f4a5b6c",
    "sku": "HX-8510",
    "name": "Hex bolt M10 x 50 zinc",
    "description": "Grade 8.8, zinc plated, fully threaded.",
    "brandId": "a1b2c3d4-0000-4000-8000-000000000001",
    "categoryId": "a1b2c3d4-0000-4000-8000-000000000002",
    "manufacturerRef": "DIN933-M10-50",
    "unitLabel": "Box of 100",
    "minOrderQty": 1,
    "availability": "in_stock",
    "leadTimeNote": null,
    "active": true,
    "visibility": "all",
    "details": { "Finish": "Zinc", "Thread": "M10" },
    "createdAt": "2026-08-14T09:30:00.000Z",
    "updatedAt": "2026-09-20T16:02:11.000Z",
    "brand": "Northgate",
    "category": "Bolts",
    "price": {
      "unit": 1573,
      "line": 7865,
      "list": 1850,
      "discountBp": 1500,
      "source": "brand",
      "label": "Brand discount −15%"
    }
  },
  "currency": "GBP"
}
```

Um ein Produkt anhand der SKU zu suchen, verwenden Sie `GET /products?q=HX-8510`: eine exakte SKU-Übereinstimmung wird immer zuerst angezeigt. Oder verwenden Sie [`GET /prices`](/docs/api/prices), das eine SKU annimmt.

## Produkt erstellen oder aktualisieren

**PUT** `/api/v1/products`

Senden Sie bis zu **100 Produkte** pro Aufruf. Jedes wird anhand der SKU mit einem vorhandenen Produkt abgeglichen, unabhängig von der Groß-/Kleinschreibung. Wenn keine Übereinstimmung vorliegt, wird ein neues Produkt erstellt. Marken und Kategorien werden anhand des Namens abgeglichen und erstellt, wenn sie nicht vorhanden sind.

### Wie Listenpreise behandelt werden

| Das Produkt…                          | Was passiert mit dem Preis                                                                                                                                                                                                             |
| ------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ist neu                               | Wird sofort bei `listPrice` live.                                                                                                                                                                                                      |
| existiert, hat aber noch keinen Preis | Wird sofort bei `listPrice` live.                                                                                                                                                                                                      |
| existiert mit dem gleichen Preis      | Nichts.                                                                                                                                                                                                                                |
| existiert mit einem anderen Preis     | Nichts ändert sich noch. Der neue Preis geht in eine **Entwurfpreisänderung** für diese Liste. `priceChangeId` ist der Entwurf für die Liste von `listPrice`. `priceChangesByList` hat einen Eintrag pro Liste, die sich geändert hat. |

Entwurfpreisänderungen sind der Weg, auf dem TradeCatalog einen Tippfehler daran hindert, Kunden zu erreichen. Der Besitzer oder das Personal überprüft den Entwurf in der App (**Preisänderungen**), prüft die größten Bewegungen und Warnungen, wählt ein Datum und ob Kunden per E-Mail benachrichtigt werden sollen, und veröffentlicht dann. Sie können einen Entwurf mit [`GET /price-changes/{id}`](/docs/api/price-changes#preview-a-price-change) vorab ansehen.

**Eine Synchronisierung, ein Entwurf pro Liste:** Ein Aufruf, der Preise ändert, startet einen Entwurf pro Liste, der „API-Import (Schlüsselname)“ genannt wird für Standard und mit dem Listenamen, wenn Sie mehr als eine senden. Um einen gesamten Sync in diesen Entwürfen zu halten, senden Sie `priceChangeId` (die Liste für `listPrice`) und `drafts` (die anderen Listen) aus dem ersten Aufruf mit jedem späteren Aufruf. Jeder muss immer noch ein Entwurf sein: sobald er veröffentlicht, storniert oder verworfen wurde, lassen Sie diese ID aus, um einen neuen zu starten.

### Körper

| Feld                         | Typ                    | Erforderlich | Beschreibung                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| ---------------------------- | ---------------------- | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `products`                   | array                  | ja           | 1 bis 100 Produkte. SKUs müssen innerhalb des Aufrufs eindeutig sein.                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `priceChangeId`              | string                 | nein         | Ein Entwurf für die Liste `listPrice` aus einem früheren Aufruf. Geänderte Preise für diese Liste werden ihm hinzugefügt. 404, wenn er nicht existiert, 400, wenn er nicht mehr ein Entwurf ist.                                                                                                                                                                                                                                                                                             |
| `drafts`                     | array                  | nein         | Bis zu 30 Einträge von `{ list, priceChangeId }`, damit andere Listen ihre eigenen Entwürfe fortsetzen.                                                                                                                                                                                                                                                                                                                                                                                      |
| `products[].sku`             | Zeichenfolge           | ja           | Bis zu 64 Zeichen.                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `products[].name`            | Zeichenfolge           | ja           | Bis zu 200 Zeichen.                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| `products[].listPrice`       | Ganzzahl oder null     | ja           | Kleine Einheiten, 0 bis 1.000.000.000. `null` ist Preis auf Anfrage: Ein neues Produkt hat keinen Preis, ein vorhandenes behält seinen eigenen.                                                                                                                                                                                                                                                                                                                                              |
| `products[].priceList`       | Zeichenfolge oder null | nein         | Name einer vorhandenen Preisliste für `listPrice`. Weglassen oder `null` ist Standard. Ein unbekannter Name wird abgelehnt.                                                                                                                                                                                                                                                                                                                                                                  |
| `products[].listPrices`      | Array                  | nein         | Andere Listen, wie `{ list, price }`. `price` ist kleine Einheiten, oder `null`, um diese Liste unverändert zu lassen. Ein unbekannter Name wird abgelehnt.                                                                                                                                                                                                                                                                                                                                  |
| `products[].unitLabel`       | Zeichenfolge           | ja           | Bis zu 60 Zeichen, z. B. „Stück“.                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `products[].brand`           | Zeichenfolge           | nein         | Markenname, bis zu 120 Zeichen. **Wird gelöscht, wenn nicht angegeben.**                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `products[].category`        | Zeichenfolge           | nein         | Kategorienname, bis zu 120 Zeichen. **Wird gelöscht, wenn nicht angegeben.**                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `products[].manufacturerRef` | Zeichenfolge           | nein         | Bis zu 120 Zeichen. **Wird gelöscht, wenn nicht angegeben.**                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `products[].description`     | Zeichenfolge           | nein         | Bis zu 4.000 Zeichen. **Wird gelöscht, wenn nicht angegeben.**                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `products[].availability`    | Zeichenfolge           | nein         | Einer der Verfügbare-Werte. Wird beibehalten, wenn nicht angegeben; neue Produkte beginnen als `not_tracked`.                                                                                                                                                                                                                                                                                                                                                                                |
| `products[].stockQty`        | Ganzzahl oder null     | nein         | Lagerbestand, von -1.000.000 bis 1.000.000.000. Setzt `availability` (siehe Produktobjekt); ein Status, den Sie zusammen mit ihm senden, wird ignoriert, außer `made_to_order`. Wird beibehalten, wenn nicht angegeben, es sei denn, Sie senden ein `availability` ohne es: Dann wird der Bestand gelöscht und dieser Status wird verwendet. `null` stoppt das Zählen; der `availability`, der in derselben Zeile gesendet wird, gilt, oder der aktuelle Status, falls keiner vorhanden ist. |
| `products[].lowStockAt`      | Ganzzahl oder null     | nein         | Niedrigster Lagerbestand für dieses Produkt, von 0. `null` verwendet den Arbeitsbereichsniveau (Einstellungen, 5 als Startwert). Wird beibehalten, wenn nicht angegeben.                                                                                                                                                                                                                                                                                                                     |
| `products[].leadTimeNote`    | Zeichenfolge           | nein         | Bis zu 200 Zeichen. Wird beibehalten, wenn nicht angegeben.                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `products[].dealText`        | string                 | nein         | Bis zu 200 Zeichen, neben dem Preis angezeigt. Wird beibehalten, wenn ausgelassen.                                                                                                                                                                                                                                                                                                                                                                                                           |
| `products[].details`         | object                 | nein         | Bis zu 30 zusätzliche Spalten: Namen bis zu 60 Zeichen, Werte bis zu 500. Ersetzt alle Details, wenn gesendet; wird beibehalten, wenn ausgelassen.                                                                                                                                                                                                                                                                                                                                           |
| `products[].imageUrl`        | string                 | nein         | Eine `https` Bild-URL. Wird im Hintergrund in TradeCatalog kopiert, wenn sie sich ändert. Wird beibehalten, wenn ausgelassen.                                                                                                                                                                                                                                                                                                                                                                |
| `products[].onlyFor`         | array                  | nein         | Bis zu 200 Kontonummern oder Kontaktemails. Machen Sie das Produkt sichtbar **nur** für diese Kunden, ersetzt jede frühere Liste. Wird beibehalten, wenn ausgelassen.                                                                                                                                                                                                                                                                                                                        |

**Senden Sie jedes Feld, das Sie betreut:** `brand`, `category`, `manufacturerRef` und `description` werden wie gesendet geschrieben, also lässt man eines aus, wird es gelöscht. Senden Sie jedes Mal das vollständige Produkt, wie eine Tabellenzeile.

Diese können noch nicht über die API geändert werden: Produkt inaktivieren, `minOrderQty`, Bild entfernen, Lead-Time-Hinweis löschen und ein Kundenprodukt erneut für alle sichtbar machen. Machen Sie dies in der App.

```bash
curl -X PUT https://tradecatalog.app/api/v1/products \
  -H "Authorization: Bearer $TRADECATALOG_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "products": [
      {
        "sku": "HX-8510",
        "name": "Hex bolt M10 x 50 zinc",
        "listPrice": 1950,
        "unitLabel": "Box of 100",
        "brand": "Northgate",
        "category": "Bolts",
        "manufacturerRef": "DIN933-M10-50",
        "availability": "in_stock",
        "details": { "Finish": "Zinc", "Thread": "M10" }
      },
      {
        "sku": "OAK-HNG-75",
        "name": "Oak-finish butt hinge 75mm",
        "listPrice": 695,
        "unitLabel": "Pair",
        "category": "Hinges",
        "onlyFor": ["OAK01"]
      }
    ]
  }'
```

```js
const res = await fetch('https://tradecatalog.app/api/v1/products', {
  method: 'PUT',
  headers: {
    Authorization: `Bearer ${process.env.TRADECATALOG_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ products }),
})
const { data: result } = await res.json()
if (result.priceChangeId)
  console.log('Review the draft price change in TradeCatalog')
```

```json
{
  "data": {
    "created": 1,
    "updated": 1,
    "priceChanges": 1,
    "priceChangeId": "c4d5e6f7-1234-4abc-9def-0123456789ab",
    "priceChangesByList": [
      {
        "list": "Standard",
        "priceChangeId": "c4d5e6f7-1234-4abc-9def-0123456789ab"
      }
    ],
    "unknownCustomers": []
  }
}
```

| Feld                 | Beschreibung                                                                                           |
| -------------------- | ------------------------------------------------------------------------------------------------------ |
| `created`            | Neue Produkte.                                                                                         |
| `updated`            | Bestehende Produkte, die anhand der SKU übereinstimmen.                                                |
| `priceChanges`       | Wie viele Preise in einen Entwurf eingegangen sind, über alle Listen in dem Aufruf.                    |
| `priceChangeId`      | Der Entwurf für die `listPrice`-Liste, oder `null`, wenn diese Liste keine Änderungen hatte.           |
| `priceChangesByList` | Ein `{ list, priceChangeId }` für jede Liste, die in diesem Aufruf einen Preisanpassung hatte.         |
| `unknownCustomers`   | Werte in `onlyFor`, die keinem Kunden entsprachen (maximal 50). Diese Kunden erhielten keinen Zugriff. |

Änderungen werden im Aktivitätsprotokoll als Name des Schlüssels angezeigt, und die Suche wird sofort aktualisiert.

## Marken und Kategorien

**GET** `/api/v1/brands`

**GET** `/api/v1/categories`

Beide geben jede Zeile zurück, nach Namen sortiert, ohne Paging. Nutzen Sie die IDs mit den `brand`- und `category`-Filtern auf `GET /products`.

```bash
curl https://tradecatalog.app/api/v1/categories \
  -H "Authorization: Bearer $TRADECATALOG_API_KEY"
```

```js
const res = await fetch('https://tradecatalog.app/api/v1/categories', {
  headers: { Authorization: `Bearer ${process.env.TRADECATALOG_API_KEY}` },
})
const { data: categories } = await res.json()
```

```json
{
  "data": [
    { "id": "a1b2c3d4-0000-4000-8000-000000000002", "name": "Bolts" },
    { "id": "a1b2c3d4-0000-4000-8000-000000000003", "name": "Hinges" }
  ]
}
```

Um eine Marke oder Kategorie zu erstellen, benennen Sie sie auf einem Produkt in `PUT /products`.
