# Fouten

> De foutstructuur, elke foutcode en hoe u veilig opnieuw kunt proberen.

Fouten gebruiken normale HTTP-statuscodes en een JSON-tekst met een stabiele `code` die je in je code kunt controleren, en een `message` die voor mensen is geschreven.

```json
{
  "error": {
    "code": "validation_error",
    "message": "Some fields are invalid.",
    "issues": [
      {
        "path": "products.0.listPrice",
        "message": "Too small: expected number to be >=0"
      }
    ]
  }
}
```

`issues` is alleen daar voor `validation_error`. Elke probleem `path` wijst naar het veld, met lijstposities gecntt vanaf 0.

## Foutcodes

| Status | Code                  | Wat is er gebeurd                                                                                                    | Wat te doen                                                                              |
| ------ | --------------------- | -------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| 400    | `validation_error`    | Een queryparameter of bodyveld ontbreekt of is ongeldig.                                                             | Corrigeer de velden vermeld in `issues`.                                                 |
| 400    | `invalid_json`        | De body is geen geldige JSON.                                                                                        | Stuur JSON met `Content-Type: application/json`.                                         |
| 400    | `invalid_request`     | De aanvraag is geldig, maar niet toegestaan op dit moment, bijvoorbeeld een nieuwe bestelling als voltooid markeren. | Lees `message`; probeer niet opnieuw met onveranderde gegevens.                          |
| 401    | `unauthorized`        | Gebrek aan, onbekende of ingetrokken API-sleutel.                                                                    | Controleer de `Authorization: Bearer` header en of de sleutel nog actief is.             |
| 401    | `key_owner_removed`   | De persoon die de sleutel heeft gemaakt, is uit de workspace vertrokken.                                             | Maak een nieuwe sleutel aan van iemand die nog toegang heeft.                            |
| 403    | `insufficient_scope`  | Een sleutel met alleen-lezen probeert te schrijven.                                                                  | Gebruik een sleutel met Lezen & schrijven.                                               |
| 403    | `read_only`           | API-schrijven zijn op dit moment niet beschikbaar op de huidige Free-entiteit van de workspace.                      | De eigenaar beheert het abonnement op de website. Bestaande sleutels kunnen nog lezen.   |
| 403    | `forbidden`           | De persoon die de sleutel heeft gemaakt, is niet gemachtigd om dat te doen.                                          | Vraag een workspace-eigenaar, of maak een sleutel aan van iemand met die machtiging.     |
| 403    | `workspace_suspended` | TradeCatalog heeft de workspace gesuspendeerd. De eigenaar is per e-mail geïnformeerd over de reden.                 | Sleutels werken weer wanneer de suspensie wordt opgeheven.                               |
| 404    | `not_found`           | Geen dergelijke eindpunt, of geen dergelijke product, klant, bestelling of prijsverandering in deze workspace.       | Controleer de id, SKU of accountcode.                                                    |
| 405    | `method_not_allowed`  | De pad bestaat, maar niet met deze methode.                                                                          | Gebruik een methode van de `Allow` header.                                               |
| 429    | `rate_limited`        | Meer dan 120 aanvragen per minuut met deze sleutel.                                                                  | Wacht voor `Retry-After` seconden (60), en probeer opnieuw.                              |
| 500    | `internal_error`      | Er is iets foutgelopen aan onze kant.                                                                                | Probeer opnieuw met backoff. Als het blijft gebeuren, neem contact op met ondersteuning. |

ID’s van een ander werkruimte geven altijd `404 not_found`, nooit iemand anders’ gegevens.

## Opnieuw proberen

Herprobeer `429` en `5xx` antwoorden met backoff. Herprobeer geen andere `4xx` antwoorden: ze zullen op dezelfde manier falen.

Alle API schrijfbewerkingen zijn veilig om te herhalen: `PUT` matcht rijen op SKU of accountcode, en `PATCH /orders/{id}` faalt met `invalid_request` als de bestelling al verder is. Dus een herprobeer na een netwerktime-out zal niets dupliceren.

```js
async function api(path, init = {}, attempt = 0) {
  const res = await fetch(`https://tradecatalog.app/api/v1${path}`, {
    ...init,
    headers: {
      Authorization: `Bearer ${process.env.TRADECATALOG_API_KEY}`,
      'Content-Type': 'application/json',
      ...init.headers,
    },
  })
  if ((res.status === 429 || res.status >= 500) && attempt < 5) {
    const wait = Number(res.headers.get('Retry-After')) || 2 ** attempt
    await new Promise((resolve) => setTimeout(resolve, wait * 1000))
    return api(path, init, attempt + 1)
  }
  const body = await res.json()
  if (!res.ok) {
    const error = new Error(`${body.error.code}: ${body.error.message}`)
    error.status = res.status
    error.code = body.error.code
    error.issues = body.error.issues
    throw error
  }
  return body
}
```

## Algemene berichten

| Verzoek                                                  | Status en bericht                                                               |
| -------------------------------------------------------- | ------------------------------------------------------------------------------- |
| `GET /prices` met een onbekende SKU                      | `404` “Geen product met SKU HX-9999”                                            |
| Elk eindpunt met een onbekende klant                     | `404` “Klant OAK99 niet gevonden”                                               |
| `PATCH /orders/{id}` nieuw → voltooid                    | `400` “Een bestelling die is ontvangen kan niet als voltooid worden gemarkeerd” |
| `PATCH /orders/{id}` naar geannuleerd met geen opmerking | `400` “Geef een reden voor annulering”                                          |
| `PUT /products` met dezelfde SKU tweemaal                | `400` validatiefout “Dubbele SKU hx-8510”                                       |
