> ## Documentation Index
> Fetch the complete documentation index at: https://userepass.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Paginação

> Paginação por cursor em todos os endpoints de listagem.

Todos os endpoints de listagem da API Repass usam **paginação por cursor**, com o mesmo conjunto de parâmetros e o mesmo envelope de resposta. Como os IDs de recurso são ordenáveis (prefixo + ULID), eles próprios servem de cursor: você nunca calcula offsets nem números de página.

## Parâmetros de query

Toda listagem aceita os mesmos três parâmetros, mais [`expand[]`](/docs/convencoes/expand) para materializar relacionamentos.

<ParamField query="limit" type="integer" default="25">
  Quantidade de itens por página, entre `1` e `100`. Aceita string (é coagido para inteiro). Valores fora da faixa (`0`, `101`) são rejeitados com `400 parameter_invalid`.
</ParamField>

<ParamField query="starting_after" type="string">
  ID de recurso usado como cursor. Retorna a página **seguinte** ao item informado (avança para frente). Use o ID do último item da página anterior.
</ParamField>

<ParamField query="ending_before" type="string">
  ID de recurso usado como cursor. Retorna a página **anterior** ao item informado (volta para trás). Use o ID do primeiro item da página atual.
</ParamField>

Informe apenas um cursor por requisição: use `starting_after` para avançar ou `ending_before` para voltar. Sem nenhum cursor, você recebe a primeira página.

## Envelope da resposta

Toda listagem responde com o mesmo envelope `Page<T>`:

<ResponseField name="data" type="array">
  Array com os recursos da página atual (no máximo `limit` itens).
</ResponseField>

<ResponseField name="hasMore" type="boolean">
  `true` quando existe pelo menos mais uma página na direção da paginação; `false` quando esta é a última página.
</ResponseField>

```json theme={null}
{
  "data": [
    { "id": "aff_01J9Z2M3K4P5Q6R7S8T9V0W1X2", "name": "Afiliado A" },
    { "id": "aff_01J9Z2M3K4P5Q6R7S8T9V0W1X3", "name": "Afiliado B" }
  ],
  "hasMore": true
}
```

<Note>
  Os cursores (`starting_after` / `ending_before`) são **IDs de recurso opacos**: não embutem offset, timestamp ou estado decodificável. Trate-os como tokens: passe de volta exatamente o valor que veio em `data`, sem parsear nem construir cursores à mão.
</Note>

A resposta **não** inclui um campo `next_cursor` dedicado. Para avançar, você deriva o cursor do último item de `data` (`data[data.length - 1].id`) e o envia em `starting_after` na próxima requisição.

## Como funciona

Para detectar se há mais páginas, a API busca `limit + 1` linhas internamente, devolve no máximo `limit` em `data` e reporta `hasMore: true` se a linha extra existir.

```mermaid theme={null}
sequenceDiagram
    participant C as Cliente
    participant API as API Repass
    C->>API: GET /affiliates?limit=2
    API-->>C: { data: [A, B], hasMore: true }
    Note over C: cursor = id do último item (B)
    C->>API: GET /affiliates?limit=2&starting_after=B
    API-->>C: { data: [C, D], hasMore: true }
    Note over C: cursor = id do último item (D)
    C->>API: GET /affiliates?limit=2&starting_after=D
    API-->>C: { data: [E], hasMore: false }
    Note over C: hasMore: false → fim
```

## Exemplo

Listando afiliados, dois por página, com `GET /affiliates`:

<CodeGroup>
  ```bash Primeira página theme={null}
  curl https://api.userepass.com/affiliates?limit=2 \
    -H "Authorization: Bearer rstr_..."
  ```

  ```bash Próxima página theme={null}
  # starting_after = id do último item da página anterior
  curl "https://api.userepass.com/affiliates?limit=2&starting_after=aff_01J9Z2M3K4P5Q6R7S8T9V0W1X3" \
    -H "Authorization: Bearer rstr_..."
  ```
</CodeGroup>

## Iterando por todas as páginas

Avance enquanto `hasMore` for `true`, sempre usando o ID do último item como próximo cursor:

```bash Pseudo-loop (bash + curl) theme={null}
cursor=""
while true; do
  url="https://api.userepass.com/affiliates?limit=100"
  [ -n "$cursor" ] && url="$url&starting_after=$cursor"

  resp=$(curl -s "$url" -H "Authorization: Bearer rstr_...")

  echo "$resp" | jq -c '.data[]'              # processa os itens da página

  has_more=$(echo "$resp" | jq -r '.hasMore')
  [ "$has_more" = "true" ] || break           # última página → encerra

  cursor=$(echo "$resp" | jq -r '.data[-1].id')  # cursor = id do último item
done
```

<Tip>
  Use `limit=100` ao varrer coleções inteiras para reduzir o número de requisições. Para UIs paginadas, prefira páginas menores (ex.: `limit=25`, o default) e mantenha o cursor do último item para "próxima" e o do primeiro item (`ending_before`) para "anterior".
</Tip>

<Warning>
  Não derive o cursor de um item que você filtrou no cliente: passe sempre o ID de borda real retornado pela API (`data[-1].id` para avançar, `data[0].id` para voltar). Cursores são apenas IDs de recurso; qualquer string fora desse formato pode produzir resultados inesperados.
</Warning>

A referência completa de campos de cada listagem está na aba Referência da API. As regras de formato dos IDs usados como cursor estão em [IDs e recursos](/docs/convencoes/ids-e-recursos).

## Próximos passos

<CardGroup cols={2}>
  <Card title="IDs e recursos" icon="fingerprint" href="/docs/convencoes/ids-e-recursos">
    Formato dos identificadores que servem de cursor.
  </Card>

  <Card title="Expand" icon="layer-group" href="/docs/convencoes/expand">
    Materialize relacionamentos nas listagens.
  </Card>

  <Card title="Erros" icon="triangle-exclamation" href="/docs/convencoes/erros">
    Envelope de erro e o código `parameter_invalid`.
  </Card>

  <Card title="Idempotência" icon="rotate" href="/docs/convencoes/idempotencia">
    Replay seguro de requisições POST.
  </Card>
</CardGroup>
