Paginação
Modelo 1: offset (padrão da maioria das listagens)
Seção intitulada “Modelo 1: offset (padrão da maioria das listagens)”É o modelo do helper de paginação usado pelo grosso dos handlers.
Query params
Seção intitulada “Query params”GET /api/v1/alerts?status=OPEN&page=2&limit=50Authorization: Bearer $SENTINEX_JWT| Param | Default | Máximo | Notas |
|---|---|---|---|
page |
1 | n/a | Base 1. Valor menor que 1 é corrigido para 1 |
limit |
20 | 100 | Acima de 100 é truncado para 100, sem erro |
O offset é calculado no servidor como (page - 1) * limit.
Envelope
Seção intitulada “Envelope”{ "success": true, "data": [ { "id": "9c2a1b3e-…", "created_at": "2026-05-18T14:32:11Z" } ], "meta": { "page": 2, "limit": 50, "total": 137 }}Você chegou ao fim quando page * limit >= meta.total, ou quando data volta com menos itens que limit.
Variante da superfície de API key
Seção intitulada “Variante da superfície de API key”Parte da superfície /vasp/* usa offset direto em vez de page, e devolve a chave pagination em vez de meta. Exemplo medido em GET /api/v1/vasp/alerts:
GET /api/v1/vasp/alerts?status=OPEN&limit=50&offset=100X-API-Key: $SENTINEX_API_KEY{ "success": true, "data": [], "pagination": { "total": 137, "limit": 50, "offset": 100 }}Aqui o limit tem default 50 e teto 200.
Modelo 2: cursor (rotas de busca)
Seção intitulada “Modelo 2: cursor (rotas de busca)”Disponível em rotas de busca específicas, como a busca de clientes e a listagem de enrollments. O cursor não se chama cursor: o parâmetro é cursor_before, e o valor vem no campo next_cursor da resposta anterior.
GET /api/v1/clients?pagination=cursor&limit=100&cursor_before=<valor de next_cursor>Authorization: Bearer $SENTINEX_JWT| Param | Default | Máximo | Notas |
|---|---|---|---|
pagination |
vazio | n/a | Só aceita cursor. Outro valor retorna 400 |
cursor_before |
vazio | n/a | Opaco. Use exatamente como veio em next_cursor |
limit |
50 | 200 | Acima de 200 é truncado |
Envelope
Seção intitulada “Envelope”next_cursor é irmão de data, e não fica dentro de um objeto pagination:
{ "success": true, "data": [ { "id": "9c2a1b3e-…", "external_id": "ACME-001" } ], "next_cursor": "eyJjcmVhdGVkX2F0IjoiMjAyNi0wNS0xOFQxNDozMjoxMVoifQ"}Quando a lista acaba, next_cursor vem como string vazia, e não como null. Pare quando ele for falsy.
Loop até esgotar
Seção intitulada “Loop até esgotar”// Modelo cursor: pare quando next_cursor vier vazioasync function* paginarPorCursor(endpoint, params = {}) { let cursorBefore = undefined; for (;;) { const res = await api.get(endpoint, { params: { ...params, pagination: 'cursor', limit: 200, cursor_before: cursorBefore }, }); for (const item of res.data) yield item; if (!res.next_cursor) return; // "" encerra cursorBefore = res.next_cursor; }}
// Modelo offset: pare quando a página vier menor que o limiteasync function* paginarPorPagina(endpoint, params = {}) { const limit = 100; for (let page = 1; ; page++) { const res = await api.get(endpoint, { params: { ...params, page, limit } }); for (const item of res.data) yield item; if (res.data.length < limit) return; }}def paginar_por_cursor(endpoint: str, **params): cursor_before = None while True: res = api.get(endpoint, params={ **params, "pagination": "cursor", "limit": 200, "cursor_before": cursor_before, }) for item in res["data"]: yield item proximo = res.get("next_cursor") or "" if not proximo: return cursor_before = proximo
def paginar_por_pagina(endpoint: str, **params): limite = 100 pagina = 1 while True: res = api.get(endpoint, params={**params, "page": pagina, "limit": limite}) for item in res["data"]: yield item if len(res["data"]) < limite: return pagina += 1Cuidados
Seção intitulada “Cuidados”- Não troque filtros entre páginas. No modelo cursor, o cursor codifica a posição no resultset filtrado; no modelo offset, mudar filtro no meio embaralha a janela. Mudou filtro, recomece do início.
- Offset é instável sob escrita concorrente. Itens novos deslocam a janela e você pode repetir ou pular registros. Para varredura completa de dados que mudam, prefira uma janela temporal fechada (
from,to) em vez de percorrer todas as páginas. - Não decodifique o cursor. Ele é opaco e o formato pode mudar sem aviso.
- Não existe um código de erro
INVALID_CURSOR: cursor inválido cai na validação genérica de parâmetro, com400.