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

# Pagination et filtrage

> Parcourir les collections avec limit, offset et since.

Les collections — `/v1/companies` et `/v1/leads` — renvoient toutes la même
enveloppe :

```json theme={null}
{
  "total": 137,
  "limit": 50,
  "offset": 0,
  "data": [ /* … */ ]
}
```

| Champ    | Signification                                                          |
| -------- | ---------------------------------------------------------------------- |
| `total`  | Nombre d'éléments correspondant au filtre, **toutes pages confondues** |
| `limit`  | Taille de page effectivement appliquée                                 |
| `offset` | Position de la page dans le jeu de résultats                           |
| `data`   | Les éléments de la page                                                |

## Paramètres

<ParamField query="limit" type="integer" default="50">
  Nombre d'éléments par page. Minimum 1, **maximum 200**. Une valeur hors
  bornes est rejetée par un `400`, elle n'est pas silencieusement ramenée dans
  l'intervalle.
</ParamField>

<ParamField query="offset" type="integer" default="0">
  Nombre d'éléments à ignorer avant le début de la page.
</ParamField>

<ParamField query="since" type="string">
  Date ISO 8601. Ne renvoie que les éléments postérieurs.

  Le champ filtré dépend de la collection : **date de dernière visite**
  (`lastSeen`) pour les entreprises, **date de création** (`createdAt`) pour
  les leads.
</ParamField>

## Ordre de tri

Les deux collections sont triées par **score d'intention décroissant**, et cet
ordre n'est pas configurable. La première page est donc celle des comptes les
plus chauds.

<Warning>
  Ce tri a une conséquence sur la pagination : le score d'intention **évolue au
  fil des visites**. Entre la lecture de la page 1 et celle de la page 4, une
  entreprise peut avoir changé de rang, être vue deux fois, ou ne pas être vue
  du tout.

  Pour un export exhaustif, paginez rapidement, et utilisez `total` pour
  vérifier votre compte final. Pour une synchronisation régulière, préférez
  `since`, qui ne dépend pas du rang.
</Warning>

## Parcourir toutes les pages

```js theme={null}
const KEY = process.env.SPOTTRACKER_API_KEY;
const LIMIT = 200;

async function toutesLesEntreprises() {
  const out = [];
  let offset = 0;

  for (;;) {
    const url = `https://api.spottracker.fr/v1/companies?limit=${LIMIT}&offset=${offset}`;
    const res = await fetch(url, {
      headers: { Authorization: `Bearer ${KEY}` },
    });
    if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);

    const page = await res.json();
    out.push(...page.data);

    // On s'arrête sur une page incomplète plutôt que sur `total` : `total` est
    // recalculé à chaque appel et peut bouger pendant la pagination.
    if (page.data.length < LIMIT) return out;
    offset += LIMIT;
  }
}
```

<Tip>
  À 200 éléments par page et 120 requêtes par minute, vous lisez 24 000
  entreprises par minute. Il n'y a pratiquement jamais de raison de descendre
  la taille de page pour « ménager » l'API : c'est le nombre de requêtes qui
  est limité, pas le volume.
</Tip>

## Synchronisation incrémentale

```js theme={null}
// Date du dernier passage réussi, prise AVANT la lecture.
const depuis = await lireDerniereSynchro();
const debutDeCePassage = new Date().toISOString();

const url = `https://api.spottracker.fr/v1/companies?since=${depuis}&limit=200`;
// … pagination identique …

await enregistrerDerniereSynchro(debutDeCePassage);
```

Prendre l'horodatage **avant** la lecture, et non après, évite de manquer les
visites survenues pendant la pagination. Le prix à payer est un léger
recouvrement d'un passage à l'autre : traitez les éléments par `id`, de manière
idempotente.
