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

> ## Agent Instructions
> Documentazione di dentalspace. Il testo completo, incluso il riferimento API, è in /llms-full.txt. Per endpoint, campi e codici di errore la fonte di verità è openapi.json: non usare endpoint o campi non documentati.

# Paginazione

> Elenchi a cursore, sincronizzazione incrementale e risposte che dicono quanto coprono.

Gli endpoint che restituiscono un elenco usano la paginazione a cursore. La risposta ha sempre questa forma:

```json theme={null}
{
  "data": [ { "id": "…" } ],
  "nextCursor": "eyJ2IjoiMjAyNi0xMC0wMlQwOTozMDowMC4wMDBaIiwiaWQiOiI…"
}
```

| Campo | Tipo | Descrizione |
| - | - | - |
| `data` | array | Gli elementi della pagina |
| `nextCursor` | string \| null | Il cursore della pagina successiva. `null` = ultima pagina |

## Parametri

| Parametro | Tipo | Descrizione |
| - | - | - |
| `limit` | integer | Elementi per pagina, da `1` a `200`. Predefinito `50` |
| `cursor` | string | Il `nextCursor` della risposta precedente, tale e quale |
| `updatedSince` | ISO 8601 con fuso | Solo gli elementi modificati da questo istante in poi, compreso |

Un `limit` fuori intervallo o un cursore non riconosciuto rispondono `400 invalid_request`.

Il cursore è opaco: il suo contenuto non fa parte del contratto. Usalo solo con lo stesso endpoint e gli stessi filtri della richiesta che l'ha prodotto.

<Warning>
  Una pagina può contenere meno di `limit` elementi e avere comunque un `nextCursor`: succede con le chiavi limitate ad alcune sedi. Per sapere se ci sono altre pagine guarda solo `nextCursor`, mai quanti elementi sono arrivati.
</Warning>

## Scorrere tutte le pagine

```bash theme={null}
cursor=""
while :; do
  page=$(curl -s "https://api.dentalspace.ai/v1/patients?limit=200&cursor=$cursor" \
    -H "Authorization: Bearer $DS_KEY")
  echo "$page" | jq -c '.data[]'
  cursor=$(echo "$page" | jq -r '.nextCursor // empty')
  [ -z "$cursor" ] && break
done
```

## Ordine

Gli elenchi sono ordinati per ultima modifica e `id`, crescente. Una risorsa modificata mentre scorri le pagine si sposta in fondo e ricompare in una pagina successiva: nessuna risorsa si perde fra due pagine, ma la stessa può comparire due volte. Deduplica per `id` tenendo la versione più recente.

Fanno eccezione:

* `GET /appointments?sort=start`: per orario di inizio. Con questo ordine `updatedSince` non è disponibile;
* `GET /events`: per istante di pubblicazione dell'evento.

## Sincronizzazione incrementale

1. La prima volta scorri tutte le pagine senza `updatedSince`.
2. Salva l'`updatedAt` più recente che hai ricevuto.
3. Le volte successive passa quel valore in `updatedSince`.

Per sapere cosa è cambiato senza interrogare ogni elenco, usa i [webhook](/api/webhook) o `GET /events`, e rileggi solo le risorse toccate.

## Risposte che dicono quanto coprono

Una risposta non deve sembrare completa quando non lo è. Per questo:

| Dove | Come lo capisci |
| - | - |
| Elenchi | `nextCursor` non nullo = ce ne sono altri |
| Elementi dentro una risorsa (righe di una fattura, voci di un preventivo, rate di un piano) | Sempre tutti, mai tagliati |
| `GET /calendars/{id}/availability` | `window` è la finestra davvero cercata, dopo preavviso e orizzonte del calendario (`null` = niente di prenotabile in quella chiesta). `complete: true` = ci sono tutti gli orari liberi di `window`; con `complete: false` continua con `from` uguale a `nextFrom` |
| `GET /events` | Un evento che non è nato lascia al suo posto un `events.skipped`. Vedi [Webhook](/api/webhook#eventi-non-nati) |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.