Paginación
Todas las listas se recorren por cursor. No hay
offset ni page, y no es una omisión: mandarlos es un error explícito.
El sobre
Toda respuesta de lista tiene la misma forma, sin importar de qué recurso sea:
{
"object": "list",
"data": [ … ],
"hasMore": true,
"nextCursor": "eyJ2IjoxLCJzIjpbImR0IiwiMjAyNi0wOC0wMVQxMDoxMjozM1oiXX0",
"previousCursor": null,
"limit": 20,
"totalCount": null
}
Recorrer hacia adelante
Pide una página, y si hasMore es true vuelve a pedir con
startingAfter igual al nextCursor que te dieron. Para ir hacia atrás,
endingBefore con el previousCursor. Los dos son excluyentes.
GET /v1/persons?limit=20
GET /v1/persons?limit=20&startingAfter=eyJ2IjoxLCJzIjpb…
El cursor es opaco: lleva dentro el valor de orden y el identificador de la última fila, con su
tipo. No lo construyas ni lo interpretes — si lo alteras, recibes
INVALID_CURSOR.
El total se pide
totalCount viene en null salvo que mandes
includeTotal=true. Contar cuesta un recorrido completo del filtro, y la mayoría de las
pantallas no necesitan el número: pídelo solo cuando vayas a enseñarlo, y solo en la primera
carga.
Por qué no hay offset
Con offset, si alguien crea un registro mientras recorres la lista, todo se
desplaza: te saltas filas o repites otras, sin ningún error de por medio. El cursor ancla en una
fila concreta, así que insertar delante no te mueve el suelo.
Y una nota que cuesta una tarde a quien migra: ?offset=2 no se
ignora. Devuelve 400. Ignorarlo sería peor — un cliente sin migrar recorrería
la lista entera recibiendo siempre la primera página, sin un solo error y con datos incompletos que
parecen completos.
Límites
limit va de 1 a 100, con 20 por defecto. Fuera de rango es
LIMIT_OUT_OF_RANGE, y el error trae el máximo
dentro para que no tengas que buscarlo aquí.