# Paginação

Todos os endpoints de listagem usam **paginação baseada em cursor, apenas para frente**. Essa abordagem é confiável para grandes volumes de dados e lida bem com inserções concorrentes -- diferente da paginação por offset, você nunca verá registros duplicados ou faltando.

## Como Funciona

Toda resposta de listagem inclui um array `data` e um booleano `has_more`:

```json
{
  "data": [
    { "id": "cust_aaa111", "name": "Alice" },
    { "id": "cust_bbb222", "name": "Bob" },
    { "id": "cust_ccc333", "name": "Carlos" }
  ],
  "has_more": true
}
```

Quando `has_more` é `true`, passe o **`id` do último item** como `starting_after` para buscar a próxima página.

## Parâmetros

| Parâmetro | Tipo | Padrão | Descrição |
|  --- | --- | --- | --- |
| `starting_after` | string | -- | ID prefixado do último item da página anterior. Retorna itens após este. |
| `limit` | integer | 25 | Número de itens a retornar. Mín: 1, Máx: 100. |


## Exemplo Básico

```typescript Node.js
let hasMore = true;
let startingAfter: string | undefined;

while (hasMore) {
  const page = await dinie.customers.list({
    limit: 25,
    starting_after: startingAfter,
  });

  for (const customer of page.data) {
    console.log(customer.id, customer.name);
  }

  hasMore = page.has_more;
  if (page.data.length > 0) {
    startingAfter = page.data[page.data.length - 1].id;
  }
}
```

```ruby Ruby
has_more = true
starting_after = nil

while has_more
  page = dinie.customers.list(limit: 25, starting_after: starting_after)

  page.data.each { |customer| puts "#{customer.id} #{customer.name}" }

  has_more = page.has_more
  starting_after = page.data.last&.id
end
```

```python Python
has_more = True
starting_after = None

while has_more:
    page = dinie.customers.list(limit=25, starting_after=starting_after)

    for customer in page.data:
        print(customer.id, customer.name)

    has_more = page.has_more
    if page.data:
        starting_after = page.data[-1].id
```

```bash cURL
curl "https://api-dev.dinietech.io/api/v3/customers?limit=2" \
  -H "Authorization: Bearer dinie_at_..."
```

```json
{
  "data": [
    { "id": "cust_aaa111", "name": "Alice" },
    { "id": "cust_bbb222", "name": "Bob" }
  ],
  "has_more": true
}
```

Próxima página -- passe o último ID:

```bash
curl "https://api-dev.dinietech.io/api/v3/customers?limit=2&starting_after=cust_bbb222" \
  -H "Authorization: Bearer dinie_at_..."
```

```json
{
  "data": [
    { "id": "cust_ccc333", "name": "Carlos" }
  ],
  "has_more": false
}
```

## Paginação Automática com SDKs

Os SDKs fornecem iteradores de paginação automática que gerenciam o cursor `starting_after` para você. Esta é a abordagem recomendada para iterar sobre todos os itens de uma coleção.

```typescript Node.js
for await (const customer of dinie.customers.list({ limit: 100 })) {
  console.log(customer.id, customer.name);
}
```

```ruby Ruby
dinie.customers.list(limit: 100).auto_paging_each do |customer|
  puts "#{customer.id} #{customer.name}"
end
```

```python Python
for customer in dinie.customers.list(limit=100).auto_paging_iter():
    print(customer.id, customer.name)
```

> **Tip:** A paginação automática faz requisições sequenciais por baixo dos panos, buscando a próxima página somente quando você consome todos os itens da página atual. Defina `limit: 100` para minimizar o número de requisições HTTP.


## Ordenação

Alguns endpoints suportam ordenação com os parâmetros `sort` e `order`:

```bash
curl "https://api-dev.dinietech.io/api/v3/customers?sort=created_at&order=asc&limit=25" \
  -H "Authorization: Bearer dinie_at_..."
```

| Parâmetro | Padrão | Valores |
|  --- | --- | --- |
| `sort` | `created_at` | Depende do endpoint (veja a documentação do endpoint) |
| `order` | `desc` | `asc`, `desc` |


A paginação sempre percorre a ordem de classificação atual. Quando você usa `starting_after`, a API retorna itens que vêm após o ID especificado na ordem de classificação selecionada.

## Resultados Vazios

Uma coleção vazia retorna um array `data` vazio:

```json
{
  "data": [],
  "has_more": false
}
```

> **Info:** Endpoints com coleções naturalmente pequenas (webhook endpoints, credenciais de API) ainda usam o envelope padrão `{ "data": [...], "has_more": false }` por consistência.