# Prijsveranderingen

> Lijstprijsveranderingen en voorbeeld van één, inclusief wat een klant zal betalen voor en na.

Massa-aanpassingen, planning en e-mails over klantprijsveranderingen zijn alleen beschikbaar in Pro. Free kan standaardprijs spreadsheet-imports direct publiceren zonder e-mails. Bestaande overeengekomen prijzen en geplande veranderingen blijven van kracht wanneer Pro eindigt.

Lijstprijzen veranderen nooit ongemerkt in TradeCatalog. Nieuwe prijzen gaan naar een **prijsverandering** voor één prijslijst: een concept dat medewerkers beoordelen, datum en publiceren. Klanten krijgen alleen een e-mail wanneer hun eigen prijs verandert. Standard is de lijst wanneer er geen andere naam is gegeven. Een concept mengt nooit lijsten.

## Hoe prijsveranderingen worden gemaakt

- **Via de API:** [`PUT /products`](/docs/api/products#create-or-update-products) met een nieuw `listPrice` voor een bestaand product voegt het toe aan een concept en retourneert de `priceChangeId` van het concept.
- **Via de app:** spreadsheet-imports en bulkveranderingen zoals "+4% op de Bolts-categorie".

Publiceren, plannen en annuleren gebeuren in de app onder **Prijsveranderingen**. Er is geen API voor deze acties: iemand controleert altijd een prijsverandering voordat klanten het zien.

## Statussen

| Status      | Betekenis                                                                |
| ----------- | ------------------------------------------------------------------------ |
| `draft`     | Niet gepubliceerd. Geen prijzen zijn veranderd.                          |
| `scheduled` | Gepubliceerd met een toekomstige datum. Prijzen veranderen op die datum. |
| `live`      | Van toepassing.                                                          |
| `cancelled` | Geannuleerd voordat het van kracht werd.                                 |

## Het prijsverandering-object

```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
}
```

| Veld               | Type           | Beschrijving                                                                                                                           |
| ------------------ | -------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| `source`           | string         | `import` (spreadsheet of API) of `bulk` (een procentuele verandering gemaakt in de app).                                               |
| `title`            | string         | Zichtbaar voor medewerkers. API-concepten hebben de titel “API import (sleutelnaam)”.                                                  |
| `supplierNote`     | string of null | Bericht aan klanten in de e-mail over prijsverandering.                                                                                |
| `status`           | string         | Zie [statussen](#statuses).                                                                                                            |
| `effectiveAt`      | string of null | Wanneer de nieuwe prijzen van kracht zijn.                                                                                             |
| `notifyCustomers`  | boolean        | Of klanten hun nieuwe prijzen per e-mail ontvangen.                                                                                    |
| `raiseFixedPrices` | boolean        | Of overeengekomen prijzen met dezelfde procentuele stijging stijgen. Deze keuze is apart van de lijst.                                 |
| `priceListId`      | string of null | De lijst waarin deze verandering wordt geschreven. Null betekent Standard, inclusief veranderingen van voor de lijsten werden genoemd. |
| `priceListName`    | string         | De naam van die lijst. `Standard` wanneer `priceListId` null is.                                                                       |
| `createdBy`        | string or null | ID van de persoon die het heeft gemaakt. Voor API-concepten is het de persoon die de sleutel heeft gemaakt.                            |
| `items`            | integer        | Hoeveel producten het verandert. Alleen in de lijst.                                                                                   |

## Lijstprijsveranderingen

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

Nieuwste eerst. Betreft de **100 meest recente** prijsveranderingen.

| Naam     | Type    | Verplicht      | Beschrijving                               |
| -------- | ------- | -------------- | ------------------------------------------ |
| `limit`  | integer | niet verplicht | 1 tot 100. Standaard 100.                  |
| `offset` | integer | niet verplicht | Aantal rijen om te overslaan. Standaard 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')
```

## Voorbeeld van een prijsverandering

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

Alles wat medewerkers zien voordat het wordt gepubliceerd: hoeveel prijzen stijgen en dalen, de grootste bewegingen, waarschuwingen en hoeveel overeengekomen prijzen het raakt. Geef `customer` door om te zien welke prijzen de klant zelf voor en na de verandering heeft.

| Naam       | In    | Type   | Verplicht      | Beschrijving                |
| ---------- | ----- | ------ | -------------- | --------------------------- |
| `id`       | pad   | string | ja             | ID van de prijsverandering. |
| `customer` | query | string | niet verplicht | Klant-ID of accountcode.    |

```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"
}
```

| Veld            | Beschrijving                                                                                                                                                                                                         |
| --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `counts`        | Producten in de verandering, en hoeveel stijgen en dalen.                                                                                                                                                            |
| `biggest`       | Maximaal 20 items met de grootste procentuele verandering. `changeBp` is de verandering in basispunten (541 = +5,41%).                                                                                               |
| `warnings`      | Items die meer dan 30% stijgen of dalen, of naar nul gaan. Meestal typfouten.                                                                                                                                        |
| `fixedAffected` | Overeengekomen prijzen op deze producten die nu geldig zijn. Ze veranderen alleen als de verandering overeengekomen prijzen verhoogt.                                                                                |
| `customer`      | Met `customer`: de eenheidsprijzen van de klant voor en na, van hun eigen lijst en vervolgens hun aanpassing, voor maximaal de eerste 50 items. Een klant op een andere lijst blijft onveranderd. `null` zonder het. |

`404 not_found` als er geen dergelijke prijsverandering in dit werkplek bestaat.
