Paginación
Todos los endpoints de lista de la API v3 usan paginación por cursor.
Los cursores son opacos: son cadenas que solo AllSign entiende. No los construyas, no
los decodifiques y no infieras nada de su contenido — solo pásalos de vuelta tal cual. Un cursor
malformado o adivinado devuelve 400 INVALID_CURSOR.
El sobre de lista
Toda lista responde con el mismo sobre (envelope): object: "list", el
arreglo data, y los metadatos de paginación. Nunca recibes un arreglo pelón.
{
"object": "list",
"data": [ /* ... los recursos de esta página ... */ ],
"hasMore": true,
"nextCursor": "djF8Y3JlYXRlZEF0fC4uLg",
"previousCursor": null,
"limit": 20,
"totalCount": null
}
| Campo | Qué es |
|---|---|
object | Siempre "list". |
data | Los recursos de esta página, en orden. |
hasMore | true si hay más páginas después de esta. Tu señal de fin de loop. |
nextCursor | Cursor opaco para la página siguiente (o null si no hay). |
previousCursor | Cursor opaco para la página anterior (o null). |
limit | El tamaño de página efectivo que se aplicó. |
totalCount | El total de la colección — null salvo que pidas includeTotal=true. |
Parámetros
| Parámetro | Qué hace |
|---|---|
limit | Recursos por página. Rango 1–100, default 20. |
startingAfter | Cursor: trae la página después de este punto (avanzar). |
endingBefore | Cursor: trae la página antes de este punto (retroceder). |
startingAfter y endingBefore son mutuamente excluyentes:
si mandas ambos, obtienes 422 VALIDATION_ERROR. Elige una dirección por petición.
Al paginar, mantén fijos el orden y los filtros entre peticiones. Un cursor está
atado al conjunto de sort + filtros con el que lo generaste; cambiarlos a media
paginación produce resultados inconsistentes. Y recuerda: si el cursor no es válido para esa consulta,
la API responde 400 INVALID_CURSOR.
Recorrer todas las páginas
El patrón correcto es un bucle while guiado por hasMore: mientras sea
true, pasa el nextCursor de la respuesta como startingAfter de la
siguiente petición. No uses totalCount para decidir cuándo parar.
JavaScript:
async function listAll() {
const out = [];
let cursor = null;
let hasMore = true;
while (hasMore) {
const url = new URL("https://api.dev.allsign.io/v3/documents");
url.searchParams.set("limit", "100");
if (cursor) url.searchParams.set("startingAfter", cursor);
const res = await fetch(url, {
headers: { Authorization: "Bearer " + process.env.ALLSIGN_KEY },
});
const page = await res.json();
out.push(...page.data);
hasMore = page.hasMore;
cursor = page.nextCursor;
}
return out;
}
Python:
import os, requests
def list_all():
out, cursor = [], None
while True:
params = {"limit": 100}
if cursor:
params["startingAfter"] = cursor
r = requests.get(
"https://api.dev.allsign.io/v3/documents",
headers={"Authorization": f"Bearer {os.environ['ALLSIGN_KEY']}"},
params=params,
)
page = r.json()
out.extend(page["data"])
if not page["hasMore"]:
break
cursor = page["nextCursor"]
return out
cURL (una página; encadena manualmente con el nextCursor devuelto):
# Primera página
curl "https://api.dev.allsign.io/v3/documents?limit=100" \
-H "Authorization: Bearer $ALLSIGN_KEY"
# Siguiente página: pega el nextCursor de la respuesta anterior
curl "https://api.dev.allsign.io/v3/documents?limit=100&startingAfter=djF8Y3JlYXRlZEF0fC4uLg" \
-H "Authorization: Bearer $ALLSIGN_KEY"
Conteo total
totalCount es null por default. Solo se calcula si pides
includeTotal=true, y ese cálculo es caro (escanea la colección
completa). Pídelo únicamente cuando de verdad necesites mostrar un total (p.ej. "1 284 documentos"
en una UI), y nunca lo uses como condición para terminar tu loop de paginación —
para eso está hasMore.
curl "https://api.dev.allsign.io/v3/documents?limit=20&includeTotal=true" \
-H "Authorization: Bearer $ALLSIGN_KEY"
{
"object": "list",
"data": [ /* ... */ ],
"hasMore": true,
"nextCursor": "djF8Y3JlYXRlZEF0fC4uLg",
"limit": 20,
"totalCount": 1284
}