Skip to main content
GET /v1/changes returns immutable events created in the same transaction as a Nektir publication. It can be used as a statewide newest-first feed or filtered to one product with product_id or sku.

What an event means

Every event describes a difference between two published Nektir observations. Its times.retrieved_at is when Nektir retrieved the public response, while times.published_at is when the validated observation became API-visible. times.source_updated_at remains null unless Utah DABS supplies an update time. Inventory decreases are not inferred sales or purchases. Likewise, store_inventory_first_observed establishes a baseline and must not be labeled a restock. A catalog-presence transition does not establish zero inventory. The semantics field is a machine-readable guardrail:
  • reported_observation_change_not_inferred_sale applies to changed aggregate or store inventory.
  • baseline_observation_not_restock applies to the first retained store observation.
  • source_presence_change_missing_does_not_imply_zero_inventory applies to catalog-presence transitions.
  • published_value_change and published_presentation_change describe differences in the Nektir projection.

Event types

Use the comma-separated types filter when an application needs only selected event classes.

Stable pagination

Every response is capped at the publication revision in X-Publication-Revision. The first page also freezes the largest eligible event ID within that revision. Follow links.next or return meta.page.next_cursor unchanged. Events published concurrently or afterward are excluded from that pagination walk and appear when the application starts a new walk without the old cursor. History begins at meta.history.tracking_started_at; Nektir does not fabricate a backfill for time before tracking began. earliest_available_at, latest_available_at, and retained_event_count describe events matching the request filters and the first page’s frozen upper bound. retention_days states the current storage policy. Expired cursors return 410, just like other collection endpoints. The current pilot retains change events for 400 days (about 13 months). The value is returned by the API rather than assumed by clients and can be increased after measured event volume and storage cost are known. Any shorter value shown in generated examples is not the runtime policy.

Building a poller

  1. Poll without a cursor and record event id values your application has processed.
  2. Follow every links.next value to finish the frozen page set.
  3. Deduplicate by event id; delivery is read-based and should be treated as at least once by consumers.
  4. On the next poll, request a new first page. Use since as a retrieval-time optimization, not as the deduplication key.
The v1 API does not push webhooks or guarantee that every upstream intermediate state was observable. It reports only states Nektir successfully retrieved, validated, and published.