Skip to content

Pagination and sync

Every list endpoint returns pages of up to limit objects (default 25, maximum 100):

{ "object": "list", "url": "/v1/fuel_logs", "data": [ … ], "has_more": true, "next_cursor": "WyItZGF0ZSIs…" }

To get the next page, repeat the request with cursor set to next_cursor, keeping every other parameter the same. When has_more is false, next_cursor is null and you have everything. Cursors are opaque; don’t build or parse them. A cursor only works with the sort it was created under (400 validation_failed otherwise).

Cursors point at a position in a sorted list rather than an offset, so pages stay correct while objects are being added, and page 500 is as fast as page 1.

async function* listAll(path, params = {}) {
let cursor
do {
const url = new URL(`https://api.get-fleet.com/v1/${path}`)
for (const [k, v] of Object.entries({ ...params, limit: 100, ...(cursor ? { cursor } : {}) })) url.searchParams.set(k, v)
const res = await fetch(url, { headers: { Authorization: `Bearer ${process.env.FLEET_API_KEY}` } })
if (!res.ok) throw new Error(`${res.status} ${(await res.json()).code}`)
const page = await res.json()
yield* page.data
cursor = page.next_cursor
} while (cursor)
}
for await (const vehicle of listAll('vehicles', { status: 'active' })) console.log(vehicle.vehicle_number)

To mirror Fleet data into another system, don’t re-read everything each time. Read what changed:

  1. On the first run, page through everything with sort=updated_at.
  2. Remember the largest updated_at you saw.
  3. On every later run, request updated_since=<that value>&sort=updated_at and page to the end.

updated_since is inclusive, so the boundary object comes back again; upsert by id and that is harmless. Deletions don’t appear in updated_since results, so reconcile them with a periodic full read, or use statuses (disposed, cancelled) which do.

Add include_total=true for a total_count of all matching objects. It costs an extra count, so only ask for it when you show it.