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=50
devuelve 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=100Procesa
items.Si
nextCursorno esnull, pásalo en la siguiente petición con los mismos filtros y el mismosortBy:GET /{companyId}/activity?limit=100&cursor=NDgyODc3Repite 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:00
Una 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.