Delta polling & pagination
Syncing loads on a schedule — updatedSince, page math, and the one caveat that matters.
The sync recipe
Most integrations poll once or twice a day. The recommended loop:
- Call
GET /api/v1/loads?updatedSince=<cursor>&page=1&pageSize=1000. - Follow
hasMorethrough the pages, upserting each row into your system keyed byloadNumber. - Track the maximum
updatedAtyou've seen across the sweep. - Next run, set
updatedSinceto that maximum minus a small overlap (5 minutes is plenty). Duplicates are harmless because you're upserting.
curl -H "Authorization: Bearer $KEY" \
"https://www.fr8factory.com/api/v1/loads?updatedSince=2026-07-09T18:55:00Z&pageSize=1000"How updatedSince behaves
- Only loads with
updatedAt >= updatedSincereturn. updatedAtmoves only on real value changes. Our internal sync machinery re-checks loads against our TMS every few minutes, but a re-check that changes nothing does not touchupdatedAt— so your delta stays quiet when nothing happened.- Accepts an ISO 8601 date (
2026-07-01) or datetime (2026-07-01T00:00:00Z). Unparseable values get a400with details.
Pagination
pageis 1-based;pageSizedefaults to 100 and accepts up to 1000 (larger values clamp to 1000).- The envelope carries
page,pageSize,totalCount, andhasMore. - Rows are stably ordered by
(updatedAt, id)ascending, so a page boundary always falls at the same place for a fixed dataset.
The page-skew caveat
Page-number pagination over live data has one inherent hazard: if a
load is updated while you're mid-sweep, rows can shift between pages
— its updatedAt changes, which moves it later in the sort order. In
the worst case a row you haven't fetched yet moves behind your cursor
and that sweep misses it. (Rows can also duplicate across pages, which
your upsert already absorbs.)
You don't need to solve this in-sweep. The overlap in step 4 of the
recipe is the fix: anything that moved mid-sweep has, by definition, a
fresh updatedAt, so it's guaranteed to appear in your next poll's
delta. With an overlapped updatedSince and loadNumber upserts, the
loop is self-healing — a missed row stays missing for at most one poll
interval.
If you're doing a one-time full backfill and want it airtight, run the
sweep, then immediately re-query with updatedSince set to the time
the sweep started. The second pass picks up anything that moved.