Lists (fuel stations, EV charging stations, prospects, simulations) are paginated with a cursor. Every page answers { data, nextCursor, hasMore }.
Parameters
limit: items per page, from 1 to 100 (20 by default).cursor: thenextCursorof the previous page; omit it for the first page.
The page
GET
/v1/fuel-stationsScope fuel-stations:readRequest
curl "https://api.floweet.com/v1/fuel-stations?fuels=B7%2CE85&country=FR" \
-H "Authorization: Bearer $FLOWEET_API_KEY"Response 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 is true while another page follows; then pass nextCursor as cursor. On the last page, nextCursor is null.
Rules
- A cursor is opaque: do not decode it, do not build one. Its content may change without notice.
- It carries the position and the page size: with a
cursor, the page size is the cursor's, whateverlimitsays. Keep the same filters (q,fuels…) from one page to the next. - The cursor marks a position in the list, not an item: if items are added or removed while you read, an item may appear twice or be skipped. Deduplicate by
id, and run a full pass again rather than keeping a cursor for later. - An unreadable cursor answers
400 invalid_cursor: start again from the first page, withoutcursor. - Searches are not paginated: the company search (
limitfrom 1 to 100), the cheapest stations (10) and geocoding (5 at most) answer{ results }.
Invalid cursor
Response 400
{
"error": {
"code": "invalid_cursor",
"message": "This pagination cursor is invalid. Start the list again without “cursor”."
}
}Read a whole list
// Every station of a town, page by page (100 per 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);
// Deduplicate by id: a station added while reading may shift the pages.
return [...new Map(all.map((s) => [s.id, s])).values()];
}
const stations = await listAll({ q: "Rambouillet" });The same loop in Python
import os
import requests
def list_all(query):
"""Every station of a town, page by page (100 per 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"]
# Deduplicate by id: a station added while reading may shift the pages.
return list({s["id"]: s for s in items}.values())
stations = list_all({"q": "Rambouillet"})