Paginación
limit, offset y total — y cómo recorrer una lista sin perder filas.
Todos los endpoints de listado paginan igual, con limit y offset en la query string.
curl "https://api.trama.so/v1/customers?limit=50&offset=100" \
-H "Authorization: Bearer $TRAMA_API_KEY"| Parámetro | Default | Máximo |
|---|---|---|
limit | 25 | 100 |
offset | 0 | — |
Pedir más de 100 no se recorta en silencio: da un 400 con VALIDATION_FAILED. Es a propósito — un request que devuelve menos filas de las que pediste sin decírtelo es la forma en que una integración pierde datos sin que nadie se entere.
La forma de la respuesta
{
"data": [ /* … */ ],
"pagination": { "limit": 50, "offset": 100, "total": 1284 }
}total es el conteo de los filtros que mandaste, no de la organización entera. Es lo que te deja saber si hay otra página que pedir, sin tener que pedirla y recibir un array vacío.
async function traerTodo(path) {
const items = [];
let offset = 0;
for (;;) {
const res = await fetch(`https://api.trama.so${path}?limit=100&offset=${offset}`, {
headers: { Authorization: `Bearer ${process.env.TRAMA_API_KEY}` },
});
const { data, pagination } = await res.json();
items.push(...data);
offset += pagination.limit;
if (offset >= pagination.total) return items;
}
}Los offsets se te mueven abajo de los pies. Una lista es una consulta viva, no una foto: si mientras la recorrés se crean o reordenan filas —y en el catálogo, editar un producto lo reordena— una fila puede saltar de página y la vas a ver dos veces o ninguna.
Si estás sincronizando en vez de mirando, no cuentes con haber recorrido todas las páginas limpiamente. Indexá por el id del recurso y volvé a recorrer cada tanto, en vez de asumir que una pasada quedó completa.
No hay paginación por cursor, y es una decisión y no un olvido: un cursor estable necesita un orden que hoy no podemos prometer en todas las listas. Si tu catálogo o tu base de clientes crece hasta que esto duele, contanos: es de las cosas que se versionan, no que se parchan.