Pagination et synchronisation incrémentale
Parcourir une liste page par page avec un curseur, puis ne récupérer que les nouveautés à chaque passage.
Documentation de l'APIGuides · Pagination et synchronisation
Forme d'une liste
Toutes les opérations de liste renvoient le même objet :
{
"object": "list",
"data": [{ "object": "review", "id": "jd7f3k2m9x8w1q4z" }],
"hasMore": true,
"nextCursor": "eyJ2IjoxLCJjIjoi..."
}
datacontient les éléments de la page.hasMorevauttruetant qu'il reste des éléments après cette page.nextCursorest le curseur de la page suivante, ounullsur la dernière page.
Paramètres
| Paramètre | Rôle |
|---|---|
limit | Nombre d'éléments par page, de 1 à 100. 25 par défaut. |
cursor | Valeur de nextCursor reçue avec la page précédente. Absent pour la première page. |
Le curseur est opaque : ne le décodez pas et ne le fabriquez pas. Il ne se réutilise qu'avec les mêmes filtres que la requête qui l'a renvoyé : changer un filtre en cours de route répond 400 invalid_cursor. La valeur de limit, elle, peut changer d'une page à l'autre.
Un paramètre inconnu, répété ou hors bornes répond 400 invalid_request, avec le détail dans errors (par exemple query.limit : « Must be less than or equal to 100 »).
Ordre des éléments
Les avis, les retours privés et les contacts sont listés du plus récent au plus ancien. Pour les autres listes, ne vous appuyez pas sur un ordre particulier.
Parcourir toutes les pages
En JavaScript, dans un module Node 18 ou plus :
async function listAll(path, params = {}) {
const items = [];
let cursor = null;
do {
const query = new URLSearchParams({ ...params, limit: "100" });
if (cursor) query.set("cursor", cursor);
const response = await fetch(`https://api.mabellenote.com/v1${path}?${query}`, {
headers: { Authorization: `Bearer ${process.env.MBN_API_KEY}` },
});
const page = await response.json();
if (!response.ok) throw new Error(`${page.status} ${page.code} (${page.requestId})`);
items.push(...page.data);
cursor = page.nextCursor;
} while (cursor);
return items;
}
const reviews = await listAll("/reviews", { rating: "1" });
En Python, avec requests :
import os
import requests
def list_all(path, **params):
items, cursor = [], None
while True:
query = {**params, "limit": 100}
if cursor:
query["cursor"] = cursor
response = requests.get(
"https://api.mabellenote.com/v1" + path,
params=query,
headers={"Authorization": "Bearer " + os.environ["MBN_API_KEY"]},
timeout=30,
)
page = response.json()
if not response.ok:
raise RuntimeError(f"{page['status']} {page['code']} ({page['requestId']})")
items.extend(page["data"])
cursor = page["nextCursor"]
if cursor is None:
return items
Chaque page compte pour un appel dans la limite de débit : lire 1 000 avis par pages de 100 coûte 10 appels.
Filtres utiles à la synchronisation
| Filtre | Listes | Effet |
|---|---|---|
establishmentId | avis, retours privés, contacts | Ne garde que les éléments de cet établissement. |
createdAfter | avis, retours privés, contacts | Ne garde que les éléments créés à partir de cette date, incluse. |
createdBefore | avis, retours privés | Ne garde que les éléments créés jusqu'à cette date, incluse. |
includeDeleted | avis | true ne liste que les avis supprimés de la plateforme. |
Les dates s'écrivent au format ISO 8601, par exemple 2026-10-24 ou 2026-10-24T09:15:02.311Z. La référence liste tous les filtres de chaque opération.
Synchronisation incrémentale
Une première synchronisation parcourt toutes les pages. Les suivantes ne demandent que ce qui a été créé depuis :
- Conservez la date
createdAtla plus récente reçue, par ressource. - Au passage suivant, envoyez-la dans
createdAfter. La borne étant incluse, le dernier élément déjà reçu revient : dédoublonnez parid, en mettant à jour l'élément existant plutôt qu'en l'ajoutant. - Parcourez les pages jusqu'à
hasMore: false.
Un élément déjà synchronisé peut encore changer :
- Avis : une réponse publiée remplit
reply, une modification par son auteur met à jourupdatedAt, l'analyse remplitanalysis.sentimentune fois l'avis analysé, et une suppression sur la plateforme remplitdeletedAt. Relisez une fenêtre glissante récente, par exemple les 30 derniers jours, à chaque passage, et listez les avis supprimés avecincludeDeleted=true. - Contacts : les consentements, les désinscriptions et les passages modifient
updatedAt. Aucun filtre ne porte sur cette date : resynchronisez la base clients complète à intervalle régulier.
Le createdAt d'un avis est sa date de publication sur la plateforme, pas sa date d'arrivée dans
Ma Belle Note. Quand un établissement rejoint le compte, ou quand son historique est importé, des
avis anciens apparaissent avec des dates passées. Surveillez GET /v1/establishments : un nouvel
id, ou un reviews.count qui augmente plus que ce que vous avez reçu, appelle une
resynchronisation complète de cet établissement avec establishmentId.
Suivre les changements avec le journal d'événements
La relecture d'une fenêtre glissante a ses limites : elle coûte des appels et ne voit pas toutes les modifications. Le journal d'événements suit chaque changement du compte, dans l'ordre où il est publié. C'est la façon la plus sûre de rester synchronisé :
- Faites une première synchronisation complète avec les listes, comme ci-dessus.
- Lisez ensuite
GET /v1/events(droitevents:read), en conservant la positionnextCursord'un appel à l'autre.
curl "https://api.mabellenote.com/v1/events?types=review.created,review.updated,review.reply_published&limit=100" \
-H "Authorization: Bearer $MBN_API_KEY"
- Les événements arrivent du plus ancien au plus récent. Sans
after, la lecture part du plus ancien événement conservé. - Passez le
nextCursorreçu dansafterà l'appel suivant. Il n'est jamaisnull: quandhasMorevautfalse, vous êtes à jour, et ce mêmenextCursorsert au passage suivant. Conservez-le d'une synchronisation à l'autre. - Comme pour les listes, une position ne se réutilise qu'avec les mêmes filtres
typesetestablishmentId. - Chaque événement porte l'objet concerné dans sa forme publique (
data.object) : un avis, un retour privé ou un contact. Mettez à jour votre copie par sonid. - Les événements restent consultables 30 jours. Une intégration arrêtée plus longtemps repart d'une synchronisation complète.
- Les événements ne sont produits que tant qu'au moins une clé API ou un point de réception webhook du compte est actif, et jamais pour les faits antérieurs.
GET /v1/events/{eventId} relit un événement précis. Pour être prévenu sans interroger l'API, les webhooks poussent ces mêmes événements vers votre serveur, et le journal sert alors au rattrapage.
Mis à jour le 25 octobre 2026

