# Convenções

> Forma da resposta, paginação, dinheiro, porcentagens, datas, IDs, upserts, limites de taxa e versionamento.

## Requisições e respostas

- Requisições e respostas são JSON. Envie `Content-Type: application/json` com um corpo.
- Os nomes dos campos são camelCase: `listPrice`, `accountCode`, `nextOffset`.
- Parâmetros de consulta são strings simples: `?limit=20&status=new`.

Toda resposta bem-sucedida é um objeto com `data`:

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

| Campo        | Quando ele está presente                            | Significado                                                                 |
| ------------ | --------------------------------------------------- | --------------------------------------------------------------------------- |
| `data`       | Sempre                                              | O objeto ou lista que você pediu.                                           |
| `nextOffset` | Listas que paginam                                  | Passe-o como `offset` para obter a próxima página. `null` na última página. |
| `currency`   | Respostas com preços na moeda do espaço de trabalho | Código ISO 4217 para cada campo de dinheiro em `data`.                      |

Pedidos carregam seu próprio campo `currency`, fixo quando o pedido foi feito.

## Paginação

Listas usam `limit` e `offset`:

| Parâmetro | Padrão   | Máximo                               |
| --------- | -------- | ------------------------------------ |
| `limit`   | o máximo | 50 para produtos, 100 para tudo mais |
| `offset`  | 0        | nenhum                               |

Continue a solicitar com `offset=nextOffset` até que `nextOffset` seja `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
}
```

No `/products`, `nextOffset` é definido sempre que uma página estiver cheia. Se o tamanho do catálogo for um múltiplo exato de `limit`, a última solicitação retorna uma lista vazia `data` com `nextOffset: null`.

Algumas listas têm limite. `GET /orders` abrange os 200 pedidos mais recentes correspondentes, e `GET /price-changes` os 100 mais recentes.

## Dinheiro

Dinheiro é um **número inteiro nas unidades menores da moeda**, então não há erro de arredondamento:

| Valor  | Moeda | Significa                |
| ------ | ----- | ------------------------ |
| `1234` | GBP   | £12.34                   |
| `1850` | EUR   | €18.50                   |
| `500`  | JPY   | ¥500 (sem unidade menor) |

Divida por 10 elevado à potência das casas decimais da moeda para exibi-lo. No JavaScript, `Intl.NumberFormat` faz isso para você:

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

Preços são os definidos pelo fornecedor em sua lista de preços. Se isso inclui imposto é definido pela `taxLabel` da workspace em [`GET /workspace`](/docs/api/workspace): por exemplo,

## Porcentagens

Porcentagens são **pontos básicos**: centésimos de porcentagem, como inteiros.

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

## Datas

Datas são strings no formato ISO 8601 em UTC, como `2026-09-27T08:15:00.000Z`. O fuso horário da workspace é `timezone` em [`GET /workspace`](/docs/api/workspace).

## IDs

IDs são strings UUID. Em qualquer lugar em que um endpoint aceite um **cliente**, você pode passar o ID do cliente ou seu código de conta (case-insensitive), conforme o que sua sistema tiver:

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

## Criando e atualizando (PUT)

`PUT /products` e `PUT /customers` criam ou atualizam em uma única chamada, até 100 linhas por vez:

- Produtos são correspondidos por **SKU** (case-insensitive).
- Clientes são correspondidos por **código de conta**, senão **e-mail**, senão **nome**.

Ambos são seguros para repetição. Enviar as mesmas linhas duas vezes dá o mesmo resultado; a segunda chamada apenas as relata como atualizadas.

Um `PUT` escreve os campos que você envia. Alguns campos de produto opcionais são limpos quando você os deixa de fora, outros são mantidos. Cada página de endpoint lista quais.

## Limites de taxa

Cada chave pode fazer **120 solicitações por minuto**. Acima disso, você recebe `429 rate_limited` com `Retry-After: 60`. Espere e tente novamente. [Erros](/docs/api/errors#retrying) tem um helper para tentar novamente.

Faça gravações em lote quando possível: uma `PUT` com 100 produtos conta como uma solicitação.

## Versionamento

A versão está no caminho: `/api/v1`.

- Dentro do v1, fazemos apenas mudanças **aditivas**: novos endpoints, novos parâmetros opcionais, novos campos nas respostas. Escreva seu código para ignorar campos que não conheça.
- Uma mudança quebradora receberá uma nova versão (`/api/v2`), mantendo o v1 em execução e anunciando a mudança no [changelog](/docs/changelog).
