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=100. - 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=100"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.
What the feed covers
The endpoint serves loads scheduled to pick up within the last 12 months. Older loads age out of the feed — size your initial backfill accordingly (there's no way to reach further back through this API).
Filtering
All filters are optional and AND-composed with your customer scope, the
12-month window, and updatedSince:
| Parameter | Effect |
|---|---|
status | Repeatable — ?status=InTransit&status=Covered matches any of the given statuses. Values must come from the closed status list. |
pickupFrom / pickupTo | ISO 8601; narrows pickDate to a span inside the 12-month window (a pickupFrom before the window floor doesn't reach further back). |
deliveryFrom / deliveryTo | ISO 8601; narrows on delDate. |
poNumber | Exact match on your PO number. |
billingRefNumber | Exact match on your billing reference. |
curl -H "Authorization: Bearer $KEY" \
"https://www.fr8factory.com/api/v1/loads?status=InTransit&status=Covered&pickupFrom=2026-06-01"Pagination
pageis 1-based;pageSizedefaults to 100 and is capped at 100 (larger values clamp to 100).- 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.