Incremental reads
On every cycle, fetch only the records created or changed since your last fetch, using the
updated_after parameter.Periodic full fetch
On a slower cadence (for example weekly), fetch everything to realign your store — a safety net that also recovers any missed deletes.
Everything below is about reading from the data layer. Make sure the data layer is enabled on the connection and that you send the
x-chift-datalayer: true header on these reads — see Activating the data layer. All examples send that header.The sync model
Run a full load once to seed your store, then keep it fresh incrementally and reconcile periodically:Initial full load
The first time, page through each resource with no
updated_after filter and upsert every record into your store. This seeds your dataset.Incremental reads
On each subsequent cycle, request the same resources with
updated_after set to the start of your previous fetch. You get back only the records that were created or changed since, and you upsert them.Incremental reads with updated_after
The accounting resources that grow over time accept an updated_after query parameter. When set, the data layer returns only the records whose last-updated timestamp is after the value you pass — created or modified records — so each incremental cycle stays small and fast regardless of how much history exists.
updated_after is available on:
- Clients (
/accounting/clients) - Suppliers (
/accounting/suppliers) - Invoices (
/accounting/invoices) - Journal entries (
/accounting/journal-entries)
cURL
- Always pass UTC. Use an ISO 8601 timestamp in UTC (for example
2024-01-31T15:00:00Z). UTC is the only format supported consistently across connectors. - Use the start of your previous fetch, not its end. Record when each cycle began, and pass that value as
updated_afternext time. This overlaps the window slightly and avoids missing records that changed while the previous fetch was running. - Reads still paginate. A large incremental window can still span several pages — keep following pagination until the page is empty. See Pagination limits.
- Upsert, don’t append. A record can come back because it was updated, so key your writes on the record id and upsert.
React to refresh webhooks
The data layer is only as fresh as its last sync, so there’s no point fetching more often than it refreshes. Instead of polling on a timer, subscribe to the datalayer webhooks and react when a refresh happens:account.datalayer.refresh_initiated— a refresh started for a consumer.account.datalayer.refresh_executed— the refresh finished for that consumer, with astatusofsuccessorerror.account.datalayer.data_changed— which resources changed in that refresh.account.datalayer.data_deleted— which records were removed from the data layer in that refresh.
account.datalayer.refresh_executed (or data_changed), trigger an incremental read with updated_after set to the start of your previous fetch and upsert the results — this keeps your store aligned without guessing the cadence. When you receive account.datalayer.data_deleted, delete the listed records from your store (see Handling deletes). See Webhooks for the payload format and how to verify the signature.
Handling deletes
updated_after returns created and changed records — it can never return a record that was deleted in the source, because a deleted record simply stops appearing in reads. Incremental reads alone will therefore let deleted records linger in your store.
The data layer surfaces deletes in two ways:
- The
account.datalayer.data_deletedwebhook (recommended). Each refresh emits this event with the records it removed, so you can drop exactly those from your store as soon as the refresh completes — no extra reads, and deletes stay as fresh as your incremental updates. - A periodic full fetch, as a safety net. On a slower cadence (weekly is a good default), fetch each resource in full and reconcile against your store: any record you hold that is absent from the full result set has been removed at the source and should be deleted (or soft-deleted) on your side. This also recovers any delete notification you might have missed.
Putting it together
A typical loop:Stay fresh
On each
account.datalayer.refresh_executed webhook (or your chosen cadence), read each incremental resource with updated_after = the start of your previous fetch, upsert the results, then store the new fetch-start timestamp. Apply any account.datalayer.data_deleted events to drop removed records.Related
Data layer overview
What the data layer is and how it stays fresh.
Activating the data layer
Enable it on a connection and use the header.