# Convenzioni

> Forma della risposta, paginazione, denaro, percentuali, date, ID, operazioni di inserimento o aggiornamento, limiti di velocità e versioning.

## Richieste e risposte

- Le richieste e le risposte sono JSON. Invia `Content-Type: application/json` con un corpo.
- I nomi dei campi sono in camelCase: `listPrice`, `accountCode`, `nextOffset`.
- I parametri di query sono stringhe semplici: `?limit=20&status=new`.

Ogni risposta riuscita è un oggetto con `data`:

```json
{
  "data": [],
  "nextOffset": 50,
  "currency": "GBP"
}
```

| Campo        | Quando è presente                                    | Significato                                                                         |
| ------------ | ---------------------------------------------------- | ----------------------------------------------------------------------------------- |
| `data`       | Sempre                                               | L'oggetto o la lista che hai richiesto.                                             |
| `nextOffset` | Liste con paginazione                                | Passala come `offset` per ottenere la pagina successiva. `null` sull'ultima pagina. |
| `currency`   | Risposte con prezzi nella valuta dell'area di lavoro | Codice ISO 4217 per ogni campo monetario in `data`.                                 |

Gli ordini portano con sé il proprio campo `currency`, fissato quando l'ordine è stato effettuato.

## Paginazione

Le liste utilizzano `limit` e `offset`:

| Parametro | Predefinito | Massimo                                   |
| --------- | ----------- | ----------------------------------------- |
| `limit`   | il massimo  | 50 per i prodotti, 100 per tutto il resto |
| `offset`  | 0           | nessuno                                   |

Continua a richiedere con `offset=nextOffset` finché `nextOffset` non è `null`:

```js
let offset = 0
const all = []
while (offset !== null) {
  const res = await fetch(
    `https://tradecatalog.app/api/v1/products?limit=50&offset=${offset}`,
    {
      headers: { Authorization: `Bearer ${process.env.TRADECATALOG_API_KEY}` },
    },
  )
  const page = await res.json()
  all.push(...page.data)
  offset = page.nextOffset
}
```

Il `/products`, `nextOffset` viene impostato ogni volta che una pagina è piena. Se la dimensione del catalogo è un multiplo esatto di `limit`, l'ultima richiesta restituisce una lista vuota `data` con `nextOffset: null`.

Alcune liste sono limitate. `GET /orders` copre i 200 ordini più recenti che corrispondono, e `GET /price-changes` i 100 più recenti.

## Denaro

Il denaro è un **intero in unità minori** della valuta, quindi non ci sono errori di arrotondamento:

| Valore | Valuta | Significa                   |
| ------ | ------ | --------------------------- |
| `1234` | GBP    | £12.34                      |
| `1850` | EUR    | €18.50                      |
| `500`  | JPY    | ¥500 (nessuna unità minore) |

Dividi per 10 elevato alla potenza dei decimali della valuta per visualizzarlo. In JavaScript, `Intl.NumberFormat` lo fa per te:

```js
const format = (minor, currency) => {
  const f = new Intl.NumberFormat('en-GB', { style: 'currency', currency })
  const digits = f.resolvedOptions().maximumFractionDigits
  return f.format(minor / 10 ** digits)
}
format(1234, 'GBP') // "£12.34"
```

I prezzi sono quelli impostati dal fornitore nella sua lista prezzi. Se includono l’imposta o meno è definito dal `taxLabel` del workspace su [`GET /workspace`](/docs/api/workspace): ad esempio “escl. IVA” (prima dell’imposta), “incl. IVA” (inclusa l’imposta), o vuoto quando il fornitore non mostra alcun riferimento all’imposta.

## Percentuali

Le percentuali sono **punti base**: centesimi di percentuale, come interi.

| Valore  | Significa |
| ------- | --------- |
| `1250`  | 12,5%     |
| `3500`  | 35%       |
| `10000` | 100%      |

## Date

Le date sono stringhe ISO 8601 in UTC, come `2026-09-27T08:15:00.000Z`. Il fuso orario del workspace è `timezone` su [`GET /workspace`](/docs/api/workspace).

## Id

Gli ID sono stringhe UUID. Ovunque un endpoint accetta un **cliente**, puoi passare l'ID del cliente o il suo codice account (non sensibile alle maiuscole), a seconda di ciò che ha il tuo sistema:

```bash
curl "https://tradecatalog.app/api/v1/prices?customer=OAK01&sku=HX-8510" \
  -H "Authorization: Bearer $TRADECATALOG_API_KEY"
```

## Creazione e aggiornamento (PUT)

`PUT /products` e `PUT /customers` creano o aggiornano in una sola chiamata, fino a 100 righe alla volta:

- I prodotti sono abbinati da **SKU** (non sensibile alle maiuscole).
- I clienti sono abbinati da **codice account**, altrimenti **email**, altrimenti **nome**.

Entrambi sono sicuri da ripetere. Inviare le stesse righe due volte dà lo stesso risultato; la seconda chiamata segnala solo che sono state aggiornate.

Un `PUT` scrive i campi che invii. Alcuni campi opzionali dei prodotti vengono cancellati quando li ometti, altri vengono mantenuti. Ogni pagina dell'endpoint elenca quali.

## Limiti di velocità

Ogni chiave può effettuare **120 richieste al minuto**. Oltre a questo, ottieni `429 rate_limited` con `Retry-After: 60`. Aspetta e riprova. [Errori](/docs/api/errors#retrying) ha un helper per il ripristino.

Effettua scritture in batch dove possibile: un `PUT` con 100 prodotti conta come una sola richiesta.

## Versioning

La versione è nel percorso: `/api/v1`.

- All'interno di v1 apportiamo solo modifiche **additive**: nuovi endpoint, nuovi parametri opzionali, nuovi campi nelle risposte. Scrivi il tuo codice in modo da ignorare i campi che non conosce.
- Un cambiamento non retrocompatibile avrebbe una nuova versione (`/api/v2`), con v1 che continua a funzionare e il cambiamento annunciato nel [changelog](/docs/changelog).
