# Errori

> La struttura degli errori, ogni codice di errore e come riprovare in modo sicuro.

Gli errori utilizzano i normali codici di stato HTTP e un corpo JSON con un `code` stabile che puoi verificare nel tuo codice, e un `message` scritto per le persone.

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

`issues` è presente solo per `validation_error`. Ogni problema ha `path` che punta al campo, con le posizioni della lista contate a partire da 0.

## Codici di errore

| Stato | Codice                | Cosa è successo                                                                                                         | Cosa fare                                                                                      |
| ----- | --------------------- | ----------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| 400   | `validation_error`    | Un parametro di query o un campo del corpo è mancante o non valido.                                                     | Correggi i campi elencati in `issues`.                                                         |
| 400   | `invalid_json`        | Il corpo non è un JSON valido.                                                                                          | Invia JSON con `Content-Type: application/json`.                                               |
| 400   | `invalid_request`     | La richiesta è valida ma non è consentita in questo momento, ad esempio contrassegnare un nuovo ordine come completato. | Leggi `message`; non ripetere senza modifiche.                                                 |
| 401   | `unauthorized`        | Chiave API mancante, sconosciuta o revocata.                                                                            | Controlla l'intestazione `Authorization: Bearer` e che la chiave sia ancora attiva.            |
| 401   | `key_owner_removed`   | La persona che ha creato la chiave ha lasciato il workspace.                                                            | Crea una nuova chiave da qualcuno che ha ancora accesso.                                       |
| 403   | `insufficient_scope`  | Una chiave in sola lettura ha provato a scrivere.                                                                       | Usa una chiave di lettura e scrittura.                                                         |
| 403   | `read_only`           | Le scritture API non sono disponibili sul piano Free attuale del workspace.                                             | Il proprietario gestisce il piano sul sito web. Le chiavi esistenti continuano a leggere.      |
| 403   | `forbidden`           | La persona che ha creato la chiave non è autorizzata a farlo.                                                           | Chiedi al proprietario del workspace, o crea una chiave da qualcuno con quella autorizzazione. |
| 403   | `workspace_suspended` | TradeCatalog ha sospeso il workspace. Il proprietario è stato informato del motivo.                                     | Le chiavi funzionano nuovamente quando la sospensione viene rimossa.                           |
| 404   | `not_found`           | Nessun endpoint esistente, o nessun prodotto, cliente, ordine o modifica prezzo in questo workspace.                    | Controlla l'id, SKU o codice account.                                                          |
| 405   | `method_not_allowed`  | Il percorso esiste ma non con questo metodo.                                                                            | Usa un metodo dall'intestazione `Allow`.                                                       |
| 429   | `rate_limited`        | Più di 120 richieste al minuto con questa chiave.                                                                       | Aspetta `Retry-After` secondi (60), quindi riprova.                                            |
| 500   | `internal_error`      | Qualcosa è andato storto nel nostro lato.                                                                               | Riprova con backoff. Se continua a verificarsi, contatta il supporto.                          |

Gli ID da un altro workspace restituiscono sempre `404 not_found`, mai i dati di qualcun altro.

## Riprova

Riprovare le risposte `429` e `5xx` con backoff. Non riprovare altre risposte `4xx`: falliranno nello stesso modo.

Tutte le scritture API sono sicure da ripetere: `PUT` cerca le righe per SKU o codice account, e `PATCH /orders/{id}` fallisce con `invalid_request` se l'ordine è già avanzato. Quindi un riprovare dopo un timeout di rete non duplicherà nulla.

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

## Messaggi comuni

| Richiesta                                     | Status e messaggio                                                       |
| --------------------------------------------- | ------------------------------------------------------------------------ |
| `GET /prices` con un SKU sconosciuto          | `404` “Nessun prodotto con SKU HX-9999”                                  |
| Qualsiasi endpoint con un cliente sconosciuto | `404` “Cliente OAK99 non trovato”                                        |
| `PATCH /orders/{id}` nuovo → completato       | `400` “Un ordine ricevuto non può essere contrassegnato come completato” |
| `PATCH /orders/{id}` annullato senza nota     | `400` “Dare un motivo per l'annullamento”                                |
| `PUT /products` con lo stesso SKU due volte   | `400` errore di convalida “SKU duplicato hx-8510”                        |
