# Preisänderungen

> Listenpreisänderungen und Voransicht einer, einschließlich dessen, was ein Kunde vor und nach der Änderung zahlt.

Massenänderungen, Terminplanung und E-Mails zu Kundenpreisänderungen erfordern Pro. Free kann Standard-Preis-Tabellenimporte sofort ohne E-Mails veröffentlichen. Bestehende vereinbarte Preise und veröffentlichte geplante Änderungen bleiben gültig, wenn Pro endet.

Listenpreise ändern sich in TradeCatalog nie unbemerkt. Neue Preise werden in eine **Preisänderung** für eine Preisliste aufgenommen: ein Entwurf, der von Mitarbeitern überprüft, datiert und veröffentlicht wird. Kunden erhalten nur dann eine E-Mail, wenn sich ihr eigener Preis ändert. Standard ist die Liste, wenn keine andere benannt wird. Ein Entwurf mischt niemals Listen.

## Wie Preiserhöhungen vorgenommen werden

- **Über die API:** [`PUT /products`](/docs/api/products#create-or-update-products) mit einem neuen `listPrice` für ein vorhandenes Produkt fügt es einem Entwurf hinzu und gibt die `priceChangeId` des Entwurfs zurück.
- **Über die App:** Tabellenimporte und Massenänderungen wie „+4 % auf die Bolzen-Kategorie“.

Veröffentlichen, Terminplanen und Stornieren erfolgen in der App unter **Preisänderungen**. Es gibt keine API dafür: eine Person überprüft immer eine Preisänderung, bevor Kunden sie sehen.

## Status

| Status      | Bedeutung                                                                           |
| ----------- | ----------------------------------------------------------------------------------- |
| `draft`     | Nicht veröffentlicht. Es haben sich keine Preise geändert.                          |
| `scheduled` | Veröffentlicht mit einem zukünftigen Datum. Die Preise ändern sich an diesem Datum. |
| `live`      | In Kraft.                                                                           |
| `cancelled` | Storniert, bevor es in Kraft trat.                                                  |

## Das Preisänderungsobjekt

```json
{
  "id": "c4d5e6f7-1234-4abc-9def-0123456789ab",
  "source": "import",
  "title": "API import (Sage stock sync)",
  "supplierNote": null,
  "status": "draft",
  "effectiveAt": null,
  "notifyCustomers": true,
  "raiseFixedPrices": false,
  "priceListId": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
  "priceListName": "Standard",
  "createdBy": "Fq3L0cZ7tN1pW9aYx2Rk",
  "publishedAt": null,
  "cancelledAt": null,
  "createdAt": "2026-09-27T02:00:14.000Z",
  "items": 38
}
```

| Feld               | Typ                    | Beschreibung                                                                                                                                              |
| ------------------ | ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `source`           | Zeichenkette           | `import` (Tabellenimport oder API) oder `bulk` (eine prozentuale Änderung, die in der App vorgenommen wurde).                                             |
| `title`            | Zeichenkette           | Wird Mitarbeitern angezeigt. API-Entwürfe erhalten den Titel „API-Import (Schlüsselname)“.                                                                |
| `supplierNote`     | Zeichenkette oder null | Nachricht an Kunden in der Preisänderungs-E-Mail.                                                                                                         |
| `status`           | Zeichenkette           | Siehe [Status](#statuses).                                                                                                                                |
| `effectiveAt`      | Zeichenkette oder null | Wann die neuen Preise gelten.                                                                                                                             |
| `notifyCustomers`  | Boolesch               | Ob Kunden ihre neuen Preise per E-Mail erhalten.                                                                                                          |
| `raiseFixedPrices` | Boolesch               | Ob vereinbarte Preise um denselben Prozentsatz ansteigen. Diese Wahl ist unabhängig von der Liste.                                                        |
| `priceListId`      | Zeichenkette oder null | Die Liste, in die diese Änderung geschrieben wird. Null bedeutet Standard, einschließlich Änderungen, die vor dem Benennen von Listen vorgenommen wurden. |
| `priceListName`    | Zeichenkette           | Der Name dieser Liste. `Standard`, wenn `priceListId` null ist.                                                                                           |
| `createdBy`        | Zeichenkette oder null | Die ID der Person, die es erstellt hat. Bei API-Entwürfen ist dies die Person, die den Schlüssel erstellt hat.                                            |
| `items`            | Ganzzahl               | Wie viele Produkte es ändert. Nur in der Liste.                                                                                                           |

## Listenpreisänderungen

**GET** `/api/v1/price-changes`

Neueste zuerst. Deckt die **100 neuesten** Preisänderungen ab.

| Name     | Typ      | Erforderlich | Beschreibung                        |
| -------- | -------- | ------------ | ----------------------------------- |
| `limit`  | Ganzzahl | nein         | 1 bis 100. Standard 100.            |
| `offset` | Ganzzahl | nein         | Zeilen zu überspringen. Standard 0. |

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

```js
const res = await fetch('https://tradecatalog.app/api/v1/price-changes', {
  headers: { Authorization: `Bearer ${process.env.TRADECATALOG_API_KEY}` },
})
const { data: changes } = await res.json()
const drafts = changes.filter((change) => change.status === 'draft')
```

## Preisänderung vorab ansehen

**GET** `/api/v1/price-changes/{id}`

Alles, was Mitarbeiter vor der Veröffentlichung sehen: wie viele Preise steigen und fallen, die größten Veränderungen, Warnungen und wie viele vereinbarte Preise betroffen sind. Geben Sie `customer` an, um die eigenen Preise dieses Kunden vor und nach der Änderung zu sehen.

| Name       | In      | Typ          | Erforderlich | Beschreibung                |
| ---------- | ------- | ------------ | ------------ | --------------------------- |
| `id`       | Pfad    | Zeichenkette | ja           | Preisänderungs-ID.          |
| `customer` | Abfrage | Zeichenkette | nein         | Kunden-ID oder Kontonummer. |

```bash
curl "https://tradecatalog.app/api/v1/price-changes/c4d5e6f7-1234-4abc-9def-0123456789ab?customer=OAK01" \
  -H "Authorization: Bearer $TRADECATALOG_API_KEY"
```

```js
const res = await fetch(
  `https://tradecatalog.app/api/v1/price-changes/${priceChangeId}?customer=OAK01`,
  { headers: { Authorization: `Bearer ${process.env.TRADECATALOG_API_KEY}` } },
)
const { data: preview } = await res.json()
if (preview.warnings.length)
  console.warn('Check these before publishing', preview.warnings)
```

```json
{
  "data": {
    "change": {
      "id": "c4d5e6f7-1234-4abc-9def-0123456789ab",
      "source": "import",
      "title": "API import (Sage stock sync)",
      "supplierNote": null,
      "status": "draft",
      "effectiveAt": null,
      "notifyCustomers": true,
      "raiseFixedPrices": false,
      "priceListId": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
      "priceListName": "Standard",
      "createdBy": "Fq3L0cZ7tN1pW9aYx2Rk",
      "publishedAt": null,
      "cancelledAt": null,
      "createdAt": "2026-09-27T02:00:14.000Z"
    },
    "counts": { "total": 38, "up": 36, "down": 2 },
    "biggest": [
      {
        "productId": "3f8a2c1e-9b4d-4e6f-a7c8-1d2e3f4a5b6c",
        "oldPrice": 1850,
        "newPrice": 1950,
        "sku": "HX-8510",
        "name": "Hex bolt M10 x 50 zinc",
        "changeBp": 541
      }
    ],
    "warnings": [],
    "fixedAffected": 3,
    "customer": {
      "name": "Oakfield Joinery",
      "rows": [
        {
          "sku": "HX-8510",
          "name": "Hex bolt M10 x 50 zinc",
          "before": 1573,
          "after": 1658,
          "label": "Brand discount −15%"
        }
      ]
    }
  },
  "currency": "GBP"
}
```

| Feld            | Beschreibung                                                                                                                                                                                                                        |
| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `counts`        | Produkte in der Änderung und wie viele steigen und fallen.                                                                                                                                                                          |
| `biggest`       | Bis zu 20 Artikel mit der größten prozentualen Veränderung. `changeBp` ist die Veränderung in Basispunkten (541 = +5,41 %).                                                                                                         |
| `warnings`      | Artikel, die sich um mehr als 30 % verändern oder auf null fallen. Meistens Tippfehler.                                                                                                                                             |
| `fixedAffected` | Vereinbarte Preise für diese Produkte, die aktuell gültig sind. Sie ändern sich nur, wenn die Änderung vereinbarte Preise erhöht.                                                                                                   |
| `customer`      | Mit `customer`: die Einzelpreise dieses Kunden vor und nach der Änderung, aus ihrer eigenen Liste und dann ihrer Anpassung, für bis zu die ersten 50 Artikel. Ein Kunde auf einer anderen Liste bleibt unverändert. `null` ohne es. |

`404 not_found`, wenn es in diesem Arbeitsbereich keine solche Preisänderung gibt.
