# Reading, paging and delta sync

> Xero pages 100 records at a time against a daily cap of 5,000 calls per organisation. QuickBooks queries 1,000 rows with a SQL-like syntax. NetSuite's REST list endpoints return ids only — use SuiteQL, or the sync will not finish.

Source: https://lopifi.com/apis/sync-and-pagination
Part of: Lopifi — US GAAP books on autopilot, reviewed by a CPA (https://lopifi.com)

---

**How do you get everything out, and then keep it fresh?** Deletes are the part everyone forgets. Only one of the three shows you them by default.

## Divergences between Xero, QuickBooks Online and NetSuite

### NetSuite REST list endpoints return ids, not records

GET /record/v1/invoice returns a page of { id, links } objects. Fetching 5,000 invoices that way is 5,001 calls against a concurrency limit in the single digits. This is not an optimisation problem; it is the difference between a sync that finishes and one that does not.

**Handling:** Use SuiteQL for every bulk read. Reserve the REST record service for single-record reads and for writes.

### Deletes are invisible in two of the three

Xero never truly deletes — it flips a status, so a delta sync sees it. QBO surfaces deletes only through change data capture, which looks back 30 days at most, so a poll-only integration — or one that was offline for a month — accumulates ghost records forever. NetSuite hard-deletes and the record simply stops existing.

**Handling:** Poll for changes, but reconcile the id set periodically: fetch all ids for a window and mark anything missing as gone. Without that pass, aging reports quietly include documents that no longer exist.

### Xero's daily cap makes backfill a scheduling problem

Xero allows 5,000 calls per organisation per day (1,000 on the free Starter tier), 60 per minute and five in flight. A full history for a large organisation cannot be fetched in one day. Any sync that assumes it can complete in one run will fail partway through and, if it is not resumable, start again from the beginning tomorrow. Paid tiers also meter monthly egress — the bytes your GETs download — so re-reading unchanged history now costs money as well as time.

**Handling:** Persist a cursor per endpoint — the Journals offset, the highest UpdatedDateUTC — and resume from it. Show sync progress to the user as a real, multi-day state.

### Modified-since is whole-record, not field-level

All three tell you a record changed and none tells you what changed. A trivial edit re-delivers the whole document, and a sync that recomputes downstream state on every delivery does a great deal of unnecessary work.

**Handling:** Hash the normalised record and skip downstream work when the hash is unchanged. It also gives you the before-and-after that QBO's missing audit trail does not.
