Les listes (stations carburant, bornes de recharge, prospects, simulations) sont paginées par curseur. Chaque page répond { data, nextCursor, hasMore }.
Paramètres
limit: éléments par page, de 1 à 100 (20 par défaut).cursor: lenextCursorde la page précédente ; absent pour la première page.
La page
GET
/v1/fuel-stationsScope fuel-stations:readRequête
curl "https://api.floweet.com/v1/fuel-stations?fuels=B7%2CE85&country=FR" \
-H "Authorization: Bearer $FLOWEET_API_KEY"Réponse 200
{
"data": [
{
"id": "28898708-4170-48bb-a3f5-e9b0d5d7ee53",
"name": "Carrefour",
"brand": "Carrefour",
"city": "Rambouillet",
"postalCode": "78120",
"country": "FR",
"fuels": [
"B7",
"GPL",
"SP95",
"SP95_E10",
"SP98"
],
"services": [],
"open24h": true,
"prices": {
"B7": {
"price": 2409,
"updatedAt": "2026-10-24T20:51:00+00:00"
},
"GPL": {
"price": 1102,
"updatedAt": "2026-10-24T20:51:00+00:00"
},
"SP95": {
"price": 2159,
"updatedAt": "2026-10-24T20:51:00+00:00"
},
"SP98": {
"price": 2225,
"updatedAt": "2026-10-24T20:51:00+00:00"
},
"SP95_E10": {
"price": 2119,
"updatedAt": "2026-10-24T20:51:00+00:00"
}
}
}
],
"nextCursor": "eyJwIjoyLCJzIjoxfQ",
"hasMore": true
}hasMore vaut true tant qu'une page suit ; nextCursor est alors à passer dans cursor. Sur la dernière page, nextCursor vaut null.
Règles
- Un curseur est opaque : ne le décodez pas, ne le fabriquez pas. Son contenu peut changer sans préavis.
- Il porte la position et la taille de la page : avec un
cursor, la taille de la page est celle du curseur, quel que soitlimit. Gardez les mêmes filtres (q,fuels…) d'une page à l'autre. - Le curseur repère une position dans la liste, pas un élément : si des éléments sont ajoutés ou supprimés pendant votre parcours, un élément peut apparaître deux fois ou être sauté. Dédupliquez par
id, et relancez un parcours complet plutôt que de garder un curseur pour plus tard. - Un curseur illisible répond
400 invalid_cursor: reprenez à la première page, sanscursor. - Les recherches ne sont pas paginées : la recherche d'entreprises (
limitde 1 à 100), les stations les moins chères (10) et le géocodage (5 au plus) répondent{ results }.
Curseur invalide
Réponse 400
{
"error": {
"code": "invalid_cursor",
"message": "Ce curseur de pagination est invalide. Reprenez la liste depuis le début, sans « cursor »."
}
}Parcourir toute une liste
// Toutes les stations d'une ville, page par page (100 par page).
async function listAll(query) {
const all = [];
let cursor;
do {
const params = new URLSearchParams({ ...query, limit: "100", ...(cursor ? { cursor } : {}) });
const res = await fetch(`https://api.floweet.com/v1/fuel-stations?${params}`, {
headers: { Authorization: `Bearer ${process.env.FLOWEET_API_KEY}` },
});
if (!res.ok) throw new Error((await res.json()).error.code);
const page = await res.json();
all.push(...page.data);
cursor = page.hasMore ? page.nextCursor : undefined;
} while (cursor);
// Dédupliquer par id : une station ajoutée pendant le parcours peut décaler les pages.
return [...new Map(all.map((s) => [s.id, s])).values()];
}
const stations = await listAll({ q: "Rambouillet" });La même boucle en Python
import os
import requests
def list_all(query):
"""Toutes les stations d'une ville, page par page (100 par page)."""
items, cursor = [], None
while True:
params = {**query, "limit": 100, **({"cursor": cursor} if cursor else {})}
res = requests.get(
"https://api.floweet.com/v1/fuel-stations",
params=params,
headers={"Authorization": f"Bearer {os.environ['FLOWEET_API_KEY']}"},
timeout=30,
)
res.raise_for_status()
page = res.json()
items.extend(page["data"])
if not page["hasMore"]:
break
cursor = page["nextCursor"]
# Dédupliquer par id : une station ajoutée pendant le parcours peut décaler les pages.
return list({s["id"]: s for s in items}.values())
stations = list_all({"q": "Rambouillet"})