# Convenios

> Forma de respuesta, paginación, dinero, porcentajes, fechas, identificadores, inserciones o actualizaciones, límites de tasa y versiones.

## Solicitudes y respuestas

- Las solicitudes y respuestas son JSON. Envíe `Content-Type: application/json` con un cuerpo.
- Los nombres de los campos son camelCase: `listPrice`, `accountCode`, `nextOffset`.
- Los parámetros de consulta son cadenas simples: `?limit=20&status=new`.

Toda respuesta exitosa es un objeto con `data`:

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

| Campo        | Cuando está presente                                       | Significado                                                                        |
| ------------ | ---------------------------------------------------------- | ---------------------------------------------------------------------------------- |
| `data`       | Siempre                                                    | El objeto o lista que solicitó.                                                    |
| `nextOffset` | Listas que pagan                                           | Pásela como `offset` para obtener la siguiente página. `null` en la última página. |
| `currency`   | Respuestas con precios en la moneda del espacio de trabajo | Código ISO 4217 para cada campo de dinero en `data`.                               |

Las órdenes llevan su propio campo `currency`, fijo cuando se colocó la orden.

## Paginación

Las listas toman `limit` y `offset`:

| Parámetro | Predeterminado | Máximo                                    |
| --------- | -------------- | ----------------------------------------- |
| `limit`   | el máximo      | 50 para productos, 100 para todo lo demás |
| `offset`  | 0              | ninguno                                   |

Sigue solicitando con `offset=nextOffset` hasta que `nextOffset` sea `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
}
```

En `/products`, `nextOffset` se establece cada vez que una página está completa. Si el tamaño del catálogo es un múltiplo exacto de `limit`, la última solicitud devuelve una lista vacía `data` con `nextOffset: null`.

Algunas listas tienen límite. `GET /orders` cubre las 200 órdenes más recientes que coinciden, y `GET /price-changes` las 100 más recientes.

## Dinero

El dinero es un **entero en unidades menores** de la moneda, por lo que no hay error de redondeo:

| Valor  | Moneda | Significa               |
| ------ | ------ | ----------------------- |
| `1234` | GBP    | £12.34                  |
| `1850` | EUR    | €18.50                  |
| `500`  | JPY    | ¥500 (sin unidad menor) |

Divide por 10 elevado a la cantidad de decimales de la moneda para mostrarlo. En JavaScript, `Intl.NumberFormat` lo hace por ti:

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

Los precios son los que el proveedor establece en su lista de precios. Si incluye impuestos depende de la configuración del espacio de trabajo `taxLabel` en [`GET /workspace`](/docs/api/workspace): por ejemplo,

## Porcentajes

Los porcentajes son **puntos básicos**: centésimas de un porcentaje, como enteros.

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

## Fechas

Las fechas son cadenas en formato ISO 8601 en UTC, como `2026-09-27T08:15:00.000Z`. La zona horaria del espacio de trabajo es `timezone` en [`GET /workspace`](/docs/api/workspace).

## Identificadores

Los identificadores son cadenas UUID. Dondequiera que un punto final tome un **cliente**, puede pasar el identificador del cliente o su código de cuenta (insensible a mayúsculas y minúsculas), según lo que tenga su sistema:

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

## Crear y actualizar (PUT)

`PUT /products` y `PUT /customers` crean o actualizan en una sola llamada, hasta 100 filas a la vez:

- Los productos se coinciden por **SKU** (sin distinción entre mayúsculas y minúsculas).
- Los clientes se coinciden por **código de cuenta**, de lo contrario **correo electrónico**, de lo contrario **nombre**.

Ambos son seguros de repetir. Enviar las mismas filas dos veces da el mismo resultado; la segunda llamada solo las reporta como actualizadas.

Un `PUT` escribe los campos que envía. Algunos campos de producto opcionales se borran cuando los omite, otros se mantienen. Cada página del punto final lista cuáles.

## Límites de velocidad

Cada clave puede realizar **120 solicitudes por minuto**. Por encima de ese límite, obtiene `429 rate_limited` con `Retry-After: 60`. Espere y pruebe de nuevo. [Errores](/docs/api/errors#retrying) tiene un ayudante para reintentar.

Escrituras por lotes donde sea posible: una `PUT` con 100 productos cuenta como una solicitud.

## Control de versiones

La versión está en la ruta: `/api/v1`.

- Dentro de v1 solo realizamos cambios **aditivos**: nuevos puntos finales, nuevos parámetros opcionales, nuevos campos en las respuestas. Escriba su código para ignorar los campos que no conozca.
- Un cambio que rompe la compatibilidad obtendrá una nueva versión (`/api/v2`), manteniendo v1 en funcionamiento y anunciando el cambio en el [registro de cambios](/docs/changelog).
