Delta synchronization

Delta synchronization

Why delta exists

Most integrations with a workforce management system are ongoing: an external payroll engine, an HR portal, or a planning dashboard needs to stay in sync with Protime data day after day. The naive approach – re-fetching every record in a collection on each run – wastes bandwidth, increases latency, and puts unnecessary load on both systems. The problem grows proportionally with the size of the workforce and the frequency of synchronization.

Delta synchronization solves this by letting the API remember where a consumer left off in the stream of changes, so subsequent requests return only the records that were created, updated, or deleted since the last call.

How change tracking works

The delta mechanism is built around a cursor that the API maintains on behalf of each consumer for each collection. The lifecycle has two phases:

Phase 1 – Initial load

When an integrator first adds the delta query parameter to a collection GET request, the API returns all records that match the current filters. Because this dataset can be large, the response is paginated: each page contains a nextLink until the final page, which instead contains a deltaLink. The deltaLink encodes an opaque cursor that marks “everything up to this point has been delivered.”

Phase 2 – Incremental updates

Subsequent requests use the deltaLink (routed through the /delta/ path). The API returns only the changes that occurred since the cursor was created. Unlike the initial load, delta responses are returned in a single, non-paginated page. Each response includes a fresh deltaLink for the next call.

  flowchart TD
    A["GET /collection?delta"] -->|"paginated response"| B["Follow nextLink pages"]
    B -->|"last page contains deltaLink"| C["Store deltaLink"]
    C --> D["GET /delta/collection?deltaToken=..."]
    D -->|"single-page response<br/>with changes"| E["Process InsertOrUpdate<br/>/ Delete"]
    E -->|"store new deltaLink"| C

Change types

Every item in a delta response carries a changeType field:

changeType Meaning
InsertOrUpdate The record was created or modified. The full current state of the record is included in data.
Delete The record was removed. Only the identifier and changeVersion are present in data.

The API deliberately collapses “insert” and “update” into a single type because the consumer’s correct action is the same in both cases: store or overwrite the record.

Ordering and deduplication with changeVersion

Each record in a delta response includes a changeVersion string. This value is string-comparable – a lexicographic comparison determines which version is newer. The changeVersion serves two purposes:

  1. Ordering – if a consumer receives the same record more than once (for example, because of a retry or overlapping requests), it can compare changeVersion values and discard the older copy.
  2. Conflict resolution – when the same record appears in both a delta response and a webhook event, the higher changeVersion wins.

If a newly received changeVersion is lexicographically less than or equal to the one already stored for the same record, the incoming change can safely be ignored.

Expiration

A delta cursor expires 72 hours after it was last used. The consumer must call the deltaLink at least once within every 72-hour window to keep the cursor alive – even if no changes are expected and the response is empty.

If the cursor expires, the API responds with 410 Gone. At that point the consumer must restart from Phase 1 (full initial load) to re-establish a cursor.

One delta per collection per consumer

The API maintains exactly one active delta cursor per collection per set of OAuth2 client credentials. Starting a new delta on the same collection implicitly replaces the previous cursor. This design prevents orphaned cursors from accumulating and ensures that the consumer always has a single, unambiguous synchronization position.

Comparison with webhooks

Delta and webhooks address the same fundamental need – staying in sync – but with different trade-offs:

Aspect Delta Webhooks
Initiation Consumer polls on its own schedule API pushes events in near-real-time
Ordering guarantee No guarantee; deduplicate with changeVersion Events may arrive out of order
Infrastructure No inbound endpoint required Consumer must expose an HTTPS endpoint
Recovery Re-fetch from last cursor Must reinitialize after expiry/disable

Many integrations use both: webhooks for low-latency awareness and delta as a periodic consistency check or fallback.

Further reading