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

# Pagination

> Parcourez les endpoints de liste Chataigne grâce à la pagination par curseur, à l'enveloppe de liste et aux filtres temporels.

Tous les endpoints de liste Chataigne renvoient une **enveloppe de liste** cohérente et utilisent une **pagination par
curseur**. Les curseurs correspondent aux identifiants de ressources existantes : la pagination reste donc stable
même si des enregistrements sont créés ou supprimés pendant le parcours.

## Enveloppe de liste

Chaque réponse de liste possède la même structure :

```json Réponse de liste theme={null}
{
  "object": "list",
  "data": [
    { "id": "scl_8Hk2...", "object": "special_closing", "...": "..." },
    { "id": "scl_3Qm9...", "object": "special_closing", "...": "..." }
  ],
  "has_more": true,
  "url": "/v1/locations/loc_9aZ.../special_closings"
}
```

<ResponseField name="object" type="string">
  Toujours égal à `"list"` pour une réponse de liste.
</ResponseField>

<ResponseField name="data" type="array">
  Tableau des objets de ressource de cette page, triés par défaut selon `created_at`.
</ResponseField>

<ResponseField name="has_more" type="boolean">
  Vaut `true` lorsque d'autres enregistrements existent après cette page. Utilisez-le comme condition d'arrêt pendant
  le parcours, sans vous fier à `data.length`.
</ResponseField>

<ResponseField name="url" type="string">
  Chemin de l'endpoint de liste à l'origine de la réponse.
</ResponseField>

## Paramètres

<ParamField query="limit" type="integer" default="10">
  Nombre d'enregistrements renvoyés par page. Il doit être compris entre `1` et `100`.
</ParamField>

<ParamField query="starting_after" type="string">
  `id` de ressource utilisé comme curseur. Renvoie la page d'enregistrements située **immédiatement après** cet objet
  dans l'ordre par défaut de `created_at`. Utilisez-le pour avancer.
</ParamField>

<ParamField query="ending_before" type="string">
  `id` de ressource utilisé comme curseur. Renvoie la page d'enregistrements située **immédiatement avant** cet objet
  dans l'ordre par défaut de `created_at`. Utilisez-le pour revenir en arrière.
</ParamField>

<Warning>
  `starting_after` et `ending_before` sont **mutuellement exclusifs**. Les envoyer dans la même requête renvoie
  `400 invalid_request_error`.
</Warning>

## Parcourir vers l'avant

Pour parcourir une liste depuis le début, demandez la première page, puis transmettez l'`id` du **dernier** élément
dans `starting_after` jusqu'à ce que `has_more` vaille `false`.

<CodeGroup>
  ```bash curl theme={null}
  # Première page
  curl https://server.chataigne.ai/v1/locations/loc_9aZ4cR2pK1/special_closings?limit=2 \
    -H "x-api-key: ch_org_live_5fK..."

  # Page suivante — transmet le dernier id de la page précédente
  curl "https://server.chataigne.ai/v1/locations/loc_9aZ4cR2pK1/special_closings?limit=2&starting_after=scl_3Qm9vT7nB4" \
    -H "x-api-key: ch_org_live_5fK..."
  ```

  ```js Node.js theme={null}
  const BASE_URL = "https://server.chataigne.ai";
  const headers = { "x-api-key": process.env.CHATAIGNE_API_KEY };

  /**
   * Récupère une page de fermetures exceptionnelles pour un établissement.
   */
  async function listSpecialClosings({ locationId, limit = 100, startingAfter }) {
    const params = new URLSearchParams({ limit: String(limit) });
    if (startingAfter) params.set("starting_after", startingAfter);
    const res = await fetch(
      `${BASE_URL}/v1/locations/${locationId}/special_closings?${params}`,
      { headers },
    );
    if (!res.ok) throw new Error(`Request failed: ${res.status}`);
    return res.json();
  }

  /**
   * Parcourt toutes les fermetures exceptionnelles d'un établissement, page par page.
   */
  async function getAllSpecialClosings(locationId) {
    const all = [];
    let startingAfter;
    while (true) {
      const page = await listSpecialClosings({ locationId, startingAfter });
      all.push(...page.data);
      if (!page.has_more) break;
      startingAfter = page.data[page.data.length - 1].id; // curseur = dernier id
    }
    return all;
  }

  const closings = await getAllSpecialClosings("loc_9aZ4cR2pK1");
  console.log(`Fetched ${closings.length} special closings`);
  ```
</CodeGroup>

<Note>
  Définissez `limit` à sa valeur maximale de `100` lors d'une synchronisation en masse afin de limiter les
  allers-retours. Conservez une valeur plus faible pour les interfaces interactives.
</Note>

## Parcourir vers l'arrière

Pour revenir vers des enregistrements plus anciens, par exemple lors d'un défilement vers le haut dans une interface,
utilisez `ending_before` avec l'`id` du **premier** élément de la page actuelle.

```bash curl theme={null}
curl "https://server.chataigne.ai/v1/locations/loc_9aZ4cR2pK1/special_closings?limit=2&ending_before=scl_8Hk2wF6dJ0" \
  -H "x-api-key: ch_org_live_5fK..."
```

## Filtres temporels

Les endpoints de liste acceptent des filtres temporels pour limiter les résultats à une période. Vous pouvez les
combiner librement avec les curseurs de pagination et `limit`.

<ParamField query="created_after" type="string">
  Renvoie uniquement les enregistrements créés strictement après cet horodatage ISO 8601.
</ParamField>

<ParamField query="created_before" type="string">
  Renvoie uniquement les enregistrements créés strictement avant cet horodatage ISO 8601.
</ParamField>

<ParamField query="updated_after" type="string">
  Renvoie uniquement les enregistrements mis à jour strictement après cet horodatage ISO 8601.
</ParamField>

<ParamField query="updated_before" type="string">
  Renvoie uniquement les enregistrements mis à jour strictement avant cet horodatage ISO 8601.
</ParamField>

Tous les horodatages utilisent le format ISO 8601 en UTC, par exemple `2026-05-01T00:00:00Z`. Les résultats restent triés selon `created_at`.

```bash curl theme={null}
# Fermetures exceptionnelles créées en mai 2026, dans une grande page adaptée à la synchronisation
curl -G "https://server.chataigne.ai/v1/locations/loc_9aZ4cR2pK1/special_closings" \
  -H "x-api-key: ch_org_live_5fK..." \
  --data-urlencode "created_after=2026-05-01T00:00:00Z" \
  --data-urlencode "created_before=2026-06-01T00:00:00Z" \
  --data-urlencode "limit=100"
```

```js Node.js theme={null}
const params = new URLSearchParams({
  created_after: "2026-05-01T00:00:00Z",
  created_before: "2026-06-01T00:00:00Z",
  limit: "100",
});
const res = await fetch(
  `https://server.chataigne.ai/v1/locations/loc_9aZ4cR2pK1/special_closings?${params}`,
  { headers: { "x-api-key": process.env.CHATAIGNE_API_KEY } },
);
const page = await res.json();
```

<Note>
  Les filtres temporels s'appliquent au même ensemble d'enregistrements que le curseur. Lorsque vous combinez
  `created_after` ou `created_before` avec `starting_after`, conservez les mêmes valeurs de filtre sur chaque page du
  parcours afin que le curseur reste cohérent.
</Note>

## Bonnes pratiques

* **Utilisez `has_more`, pas le nombre d'éléments.** Une page pleine (`data.length === limit`) peut tout de même être la dernière.
* **Traitez les curseurs comme des valeurs opaques.** Renvoyez toujours un `id` reçu dans une réponse précédente, sans jamais le construire ni le deviner.
* **Choisissez une direction.** Utilisez `starting_after` *ou* `ending_before`, jamais les deux.
* **Conservez les mêmes filtres d'une page à l'autre** pendant un parcours afin de garantir la stabilité du curseur.

<Card title="Endpoints de liste" icon="list" href="/fr/location-organization-management/overview">
  Découvrez quelles ressources peuvent être listées — organisations, établissements et fermetures exceptionnelles — ainsi que leurs champs filtrables.
</Card>
