Paginación y filtros estándar
La API pública usa tres patrones de listado distintos, no uno. Cada operación que devuelve una lista escoge el patrón que mejor encaja con el recurso. La página de cada recurso indica cuál aplica:
- Offset paginado (
{ pagination, items }) — el más común. Para recursos navegables por páginas. - Cursor paginado (
{ items, hasMore, nextCursor }) — para secuencias temporales largas (eventos de webhook, actividad, versiones). El cliente avanza pasando el cursor que recibe con cada página. - Sin paginación (
{ items }) — para catálogos pequeños y listas anidadas, donde devolver todo el conjunto de una vez es razonable.
Patrón A — Offset paginado
Aplica a la mayoría de recursos: contacts, products, invoices,
recurring, estimates, deliveryNotes, bills, payrolls, banks,
statements, paymentMethods, journal, inbox.
Parámetros
offset— posición de inicio (basada en cero). Por defecto0.limit— número máximo de resultados. Entre1y500. Si no se indica, el servidor aplica un valor por defecto razonable.
Ejemplo:
GET /{companyId}/contacts?offset=100&limit=50devuelve hasta 50 contactos a partir del 101º (índice 100).
Respuesta
{
"pagination": { "offset": 0, "limit": 50, "total": 124 },
"items": [
{ "...": "..." }
]
}pagination.offsetypagination.limitrepiten los valores efectivamente aplicados (útil cuando no envías uno y quieres saber el default).pagination.totales el total de elementos que cumplen los filtros aplicados, no el total absoluto del recurso.itemses siempre el nombre del array.
Para recorrer el resultado completo, incrementa offset en pasos de
limit hasta que offset + items.length >= total.
Para sumar en vez de recorrer: los listados de
facturas y de
facturas de compra admiten
totals=true, y la consulta analítica agrupa y compara
sin paginar.
Patrón B — Cursor paginado
Aplica a:
GET /{companyId}/activity(getActivity), el registro de actividad.GET /{companyId}/<recurso>/{id}/versions, las versiones de un documento.GET /{companyId}/webhooks/events(listPublicWebhookEvents), los eventos de webhook.
Parámetros
limit— número máximo de resultados. Máximo100.cursor— opcional. Para la primera página se omite. Para las siguientes, se envía elnextCursorque devolvió la página anterior, tal cual se recibió.
Respuesta
{
"items": [ { "...": "..." } ],
"hasMore": true,
"nextCursor": "NDgyODc3"
}itemsordenados de más reciente a más antiguo. La actividad y las versiones admiten además el orden inverso consortBy=timestamp.hasMoreindica si quedan más resultados detrás de esta página.nextCursores el cursor de la página siguiente, onullcuandohasMoreesfalse.- No hay
pagination.total. En este patrón no se devuelve el total.
Cómo paginar
- Primera petición sin
cursor:GET /{companyId}/activity?limit=100 - Procesa
items. - Si
nextCursorno esnull, pásalo en la siguiente petición con los mismos filtros y el mismosortBy:GET /{companyId}/activity?limit=100&cursor=NDgyODc3 - Repite hasta que
nextCursorseanull(o, lo que es lo mismo,hasMoreseafalse).
Notas
- El cursor es opaco. Es una cadena que identifica la posición de la
última fila de la página; su formato no forma parte del contrato y
puede cambiar. No lo construyas a partir de los datos del listado (por
ejemplo, del
iddel último elemento) ni lo interpretes: un valor que no haya devuelto la API responde400. - El cursor marca una posición, no una consulta. Si cambias los
filtros o el
sortByentre dos páginas, la petición sigue siendo válida, pero la paginación continúa desde esa posición con la nueva consulta. Para recorrer un listado completo, mantén los mismos parámetros en todas las páginas. - Para reanudar una sincronización desde un punto conocido (por ejemplo,
tras una caída), guarda el
nextCursorde la última página que procesaste con éxito y úsalo comocursoren la próxima ejecución. En la actividad y las versiones, pide ademássortBy=timestamppara avanzar hacia lo más reciente.
Patrón C — Sin paginación
Aplica a operaciones que devuelven el conjunto completo sin paginar:
- Adjuntos de documento:
getInvoiceAttachments,getRecurringInvoiceAttachments,getEstimateAttachments,getDeliveryNoteAttachments,getBillAttachments,getPayrollAttachments. - Catálogos de empresa:
getSalesTaxes,getPurchasesTaxes,getThemes,getSeries. - Listas de gestión:
listPublicWebhookEndpoints,listPublicApiKeys.
Respuesta
{
"items": [ { "...": "..." } ]
}No hay pagination ni hasMore. Asume que la cantidad de elementos es
manejable: típicamente decenas, no miles. Si un recurso de este tipo
crece más allá de lo razonable, su endpoint se migrará a uno de los
patrones paginados.
Filtros estándar de fecha
Las listas con paginación offset de facturas, presupuestos, pedidos, órdenes de compra, albaranes, nóminas, facturas de compra, facturas recurrentes, contactos, productos, bancos, métodos de pago, movimientos bancarios y campos personalizados aceptan además cuatro filtros temporales comunes:
minCreationDate/maxCreationDate— rango por fecha de creación del documento en FacturaDirecta.minModificationDate/maxModificationDate— rango por fecha de última modificación.
Los dos extremos del rango se incluyen. Cada filtro admite:
- Una fecha y hora ISO 8601 (
YYYY-MM-DDTHH:mm:ss.sssZ). Se compara el instante exacto, con su desfase horario si lo lleva (+02:00). Los:pueden ir sin codificar; el+se codifica como%2B, o llega como un espacio. - Solo la fecha (
YYYY-MM-DD). Cuenta el día entero en la zona horaria de la empresa (por defecto,Europe/Madrid): el filtro mínimo empieza en el primer instante de ese día y el máximo acaba en el último.
Ejemplos:
GET /{companyId}/invoices?minCreationDate=2026-01-01&maxCreationDate=2026-03-31
GET /{companyId}/invoices?minModificationDate=2026-04-01T08:00:00.000Z
GET /{companyId}/invoices?minModificationDate=2026-04-01T10:00:00%2B02:00Una fecha que no existe, como 2026-02-30 o 2026-02-30T00:00:00.000Z,
responde 400 con el nombre del parámetro en el mensaje. Ver
Fechas que no existen.
Estos filtros existen para detectar cambios desde un timestamp conocido
(sincronizaciones incrementales). Cada recurso documento añade además
sus propios filtros de fecha semánticos (por ejemplo minDate, maxDate
en facturas y presupuestos, sobre la fecha del documento, no la de
creación).
Ordenación
Los recursos exponen un parámetro sortBy cuando soportan ordenación
explícita. Los valores admitidos dependen del recurso y se documentan en
su página. Sin sortBy, cada recurso aplica un orden por defecto razonable
(habitualmente fecha descendente para documentos, alfabético para
catálogos).
En el patrón de cursor, los eventos de webhook tienen un orden fijo:
created_at descendente, sin sortBy. La actividad y las versiones
admiten sortBy=-timestamp (por defecto, lo más reciente primero) y
sortBy=timestamp.
Recomendaciones
- Pide solo lo que necesitas.
limit=50cubre la mayoría de casos de UI y reduce latencia. - Para sincronizaciones masivas en patrón A, filtra por
minModificationDatecon el timestamp de tu última sincronización exitosa en vez de paginar el recurso completo desde cero. - Para la actividad, las versiones y los eventos de webhook (patrón B), persiste el cursor de la última página procesada y úsalo en la siguiente sesión: no recorras todo el historial cada vez.
- Comprueba
pagination.totalantes de paginar en el patrón A; si es pequeño, una sola petición basta. - No asumas orden estable en el patrón A si no envías
sortBy. Si necesitas consistencia entre páginas, fíjalo explícitamente.