Paginação, filtros e ordenação
Todo endpoint de listagem da Ligga API aceita os mesmos parâmetros de query
string e devolve o mesmo envelope. Esta página é a referência dessas
convenções. Quais campos cada recurso aceita em sort e em filter está na
página do recurso.
Envelope de listagem
Seção intitulada “Envelope de listagem”Uma listagem devolve três chaves no primeiro nível: data com os itens,
pagination com o estado da paginação e meta com o identificador da
requisição.
{ "data": [{}, {}], "pagination": { "next_cursor": "eyJpZCI6ImMwNmQ4NzA1LWYwOTEtNDZlMS04MWJiLTRhMmNlYzY1NjY5NCIsInYiOiIyMDI2LTA1LTE4VDEyOjM0OjU2WiJ9", "has_more": true, "limit": 50 }, "meta": { "request_id": "req_9f2c1a7b4d8e4f0a91c3b5d7e2f40a68" }}| Campo | Tipo | Descrição |
|---|---|---|
pagination.next_cursor | string | null | Cursor da próxima página. null na última |
pagination.has_more | boolean | true enquanto houver página seguinte |
pagination.limit | integer | Tamanho de página efetivamente aplicado |
meta.request_id | string | Mesmo valor do cabeçalho X-Request-Id |
Paginação por cursor
Seção intitulada “Paginação por cursor”A API pagina por cursor, e não por número de página. Com ?page=2 a lista
escorrega quando um registro novo entra entre duas chamadas; com cursor, cada
página continua exatamente de onde a anterior parou.
| Parâmetro | Padrão | Descrição |
|---|---|---|
limit | 20 | Itens por página, de 1 a 100. Valor fora da faixa é ajustado para o extremo mais próximo |
cursor | — | Cursor opaco copiado de pagination.next_cursor |
A primeira chamada não leva cursor:
curl "$LIGGA_BASE/v1/customers?limit=50" \ -H "Authorization: Bearer $LIGGA_API_KEY"As seguintes repetem a mesma query string e acrescentam o cursor devolvido pela anterior:
curl "$LIGGA_BASE/v1/customers?limit=50&cursor=eyJpZCI6ImMwNmQ4NzA1LWYwOTEtNDZlMS04MWJiLTRhMmNlYzY1NjY5NCIsInYiOiIyMDI2LTA1LTE4VDEyOjM0OjU2WiJ9" \ -H "Authorization: Bearer $LIGGA_API_KEY"Repita enquanto has_more for true:
const base = process.env.LIGGA_BASE;const key = process.env.LIGGA_API_KEY;
let cursor = null;const todos = [];
do { const qs = new URLSearchParams({ limit: '100', sort: '-created_at' }); if (cursor) qs.set('cursor', cursor);
const res = await fetch(`${base}/v1/customers?${qs}`, { headers: { Authorization: `Bearer ${key}` }, }); const page = await res.json();
todos.push(...page.data); cursor = page.pagination.next_cursor;} while (cursor);Mantenha sort, filter e fields idênticos entre as páginas. O cursor
carrega o valor do campo de ordenação; trocar a ordenação no meio do percurso
produz uma sequência sem sentido.
Estrutura interna do cursor
Seção intitulada “Estrutura interna do cursor”O cursor é opaco: você o copia da resposta e nunca o constrói. A estrutura está documentada só para auditoria.
cursor = base64url( JSON({ id: "<uuid do último item>", v: "<valor do campo de sort>" }) )O par id + v desempata registros com o mesmo created_at, que é o caso
comum em importações em lote.
Ordenação
Seção intitulada “Ordenação”?sort=-created_at?sort=full_name- Prefixo
-ordena de forma decrescente. Sem prefixo, ou com+, é crescente. - Apenas um campo por requisição. Não há ordenação composta.
- O padrão é
-created_atem todos os recursos. created_ateupdated_atvalem em qualquer recurso. Os demais campos ordenáveis estão na página de cada recurso.
Um campo fora da lista devolve 422 com type validation.
Filtros
Seção intitulada “Filtros”O formato é sempre o mesmo:
?filter[<campo>][<operador>]=<valor>?filter[full_name][ilike]=Ana%&filter[is_active][eq]=true&filter[total_amount][gte]=100&filter[status][in]=paid,pendingOperadores suportados
Seção intitulada “Operadores suportados”| Operador | Significado |
|---|---|
eq | igual |
neq | diferente |
gt | maior |
gte | maior ou igual |
lt | menor |
lte | menor ou igual |
in | está na lista, separada por vírgula |
nin | não está na lista, separada por vírgula |
ilike | comparação de texto que ignora maiúsculas, com % como curinga |
is_null | true traz os nulos; false traz os não nulos |
Vários filtros na mesma requisição são combinados com AND. Não há OR, e
não há como aninhar condições.
Cada recurso declara quais campos aceitam filtro. Um campo fora dessa lista
devolve 422 com type validation em vez de ser ignorado.
Campos parciais
Seção intitulada “Campos parciais”Use fields para trazer só o que você vai usar:
?fields=id,full_name,emailApenas os campos listados voltam no objeto. id entra sempre, mesmo se você
não pedir, porque a paginação depende dele.
Relações incluídas
Seção intitulada “Relações incluídas”Alguns recursos expõem relações em include, na leitura de um item:
| Endpoint | Valores aceitos |
|---|---|
GET /v1/sales/{id} | items, status_history |
GET /v1/expenses/{id} | recurring |
curl "$LIGGA_BASE/v1/sales/c06d8705-f091-46e1-81bb-4a2cec656694?include=items,status_history" \ -H "Authorization: Bearer $LIGGA_API_KEY"Valor de include que o recurso não conhece é ignorado, sem erro. Confira a
grafia se a relação não aparecer na resposta.
Combinando tudo
Seção intitulada “Combinando tudo”curl -G "$LIGGA_BASE/v1/customers" \ -H "Authorization: Bearer $LIGGA_API_KEY" \ --data-urlencode "limit=20" \ --data-urlencode "sort=full_name" \ --data-urlencode "filter[full_name][ilike]=Ana%" \ --data-urlencode "filter[is_active][eq]=true" \ --data-urlencode "fields=id,full_name,email,phone"-G com --data-urlencode evita escapar % e [ na mão, e é a forma mais
segura de montar filtros no cURL.
Quando um parâmetro é inválido
Seção intitulada “Quando um parâmetro é inválido”Cursor corrompido, campo de ordenação desconhecido, campo de filtro não
permitido e operador inexistente caem todos na mesma resposta: 422 com
type validation e um detail que aponta o parâmetro recusado. Nenhum
deles chega ao banco.
Veja também
Seção intitulada “Veja também”- Erros — o corpo do
422e o catálogo completo - Formatos de identificador — o que é UUID, o que é opaco
- Clientes (customers) — campos ordenáveis e filtráveis de um recurso
- Exemplos em Node.js — o percurso de páginas com tratamento de erro