> ## Documentation Index
> Fetch the complete documentation index at: https://api.nektir.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Resume observed changes from a durable publication checkpoint

> With neither token, returns no events and a checkpoint covering the current publication.
Capture that checkpoint BEFORE requesting a baseline export, then poll with `checkpoint`.
Events are ordered oldest-first by publication and event within (completed checkpoint,
frozen publication]. Retrieval time is not used as a synchronization watermark.
If has_more is true, follow next_cursor alone with the same filters. Only the final page
returns a new checkpoint; commit it atomically with processing that page. Retried pages
may repeat event UUIDs. Empty filtered windows still advance the checkpoint.
Checkpoints are signed, filter-bound and independent of page-cursor and version-history TTLs.
History deletion/reset can return 410 CHECKPOINT_EXPIRED: import a new baseline.
410 CURSOR_EXPIRED instead means retry from the last completed checkpoint and deduplicate.
This is observed-product-change invalidation, not every successful retrieval or store-directory CDC.
No source requests are triggered. Family and observed-time filters are not supported here.




## OpenAPI

````yaml /openapi/v1.yaml get /changes/sync
openapi: 3.1.0
info:
  title: Independent Utah DABS API
  version: 1.0.0
  summary: Database-backed product, store, and reported-inventory reads
  description: >
    Version 1 pilot contract. All requests read a locally published database
    revision;

    no public request waits for or triggers Utah DABS. Reported quantities are

    observations, not purchase guarantees. This service is independent and is
    not

    affiliated with or endorsed by Utah DABS. The current local seed contains

    historical inventory fixtures; clients must inspect response warnings and

    coverage metadata.

    Every GET resource also supports HEAD with the same parameters, status
    codes,

    cache validators, and representation headers, but no response body.
    Conditional

    HEAD supports 304, and HEAD product details do not record product views.
servers:
  - url: http://127.0.0.1:5185/v1
    description: Local development only; set MINTLIFY_API_BASE_URL before publishing
security: []
tags:
  - name: Products
  - name: Search
  - name: Brands
  - name: Product families
  - name: Changes
  - name: Exports
  - name: Stores
  - name: Availability
  - name: Metadata
paths:
  /changes/sync:
    get:
      tags:
        - Changes
      summary: Resume observed changes from a durable publication checkpoint
      description: >
        With neither token, returns no events and a checkpoint covering the
        current publication.

        Capture that checkpoint BEFORE requesting a baseline export, then poll
        with `checkpoint`.

        Events are ordered oldest-first by publication and event within
        (completed checkpoint,

        frozen publication]. Retrieval time is not used as a synchronization
        watermark.

        If has_more is true, follow next_cursor alone with the same filters.
        Only the final page

        returns a new checkpoint; commit it atomically with processing that
        page. Retried pages

        may repeat event UUIDs. Empty filtered windows still advance the
        checkpoint.

        Checkpoints are signed, filter-bound and independent of page-cursor and
        version-history TTLs.

        History deletion/reset can return 410 CHECKPOINT_EXPIRED: import a new
        baseline.

        410 CURSOR_EXPIRED instead means retry from the last completed
        checkpoint and deduplicate.

        This is observed-product-change invalidation, not every successful
        retrieval or store-directory CDC.

        No source requests are triggered. Family and observed-time filters are
        not supported here.
      operationId: synchronizeProductChanges
      parameters:
        - $ref: '#/components/parameters/ChangeProductId'
        - $ref: '#/components/parameters/ChangeSku'
        - $ref: '#/components/parameters/ChangeStoreId'
        - $ref: '#/components/parameters/ChangeTypes'
        - name: checkpoint
          in: query
          description: >-
            Opaque completed-window token. Mutually exclusive with cursor. Omit
            both only when starting a new baseline.
          schema:
            type: string
            minLength: 1
            maxLength: 4096
        - $ref: '#/components/parameters/Cursor'
        - $ref: '#/components/parameters/Limit'
        - $ref: '#/components/parameters/IfNoneMatch'
        - $ref: '#/components/parameters/IfModifiedSince'
      responses:
        '200':
          description: >-
            Frozen ascending event page, or initial checkpoint. New completed
            checkpoint is null until the last page.
          headers:
            X-Publication-Revision:
              $ref: '#/components/headers/PublicationRevision'
            Cache-Control:
              schema:
                type: string
                const: no-store
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProductChangeSyncResponse'
        '304':
          $ref: '#/components/responses/NotModified'
        '400':
          $ref: '#/components/responses/BadRequest'
        '410':
          description: >-
            CHECKPOINT_EXPIRED requires a new baseline; CURSOR_EXPIRED permits
            replay from the last completed checkpoint. No silent gaps.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'
        '503':
          $ref: '#/components/responses/Unavailable'
components:
  parameters:
    ChangeProductId:
      name: product_id
      in: query
      description: Stable API-owned product UUID. Mutually exclusive with `sku`.
      schema:
        type: string
        format: uuid
    ChangeSku:
      name: sku
      in: query
      description: Exact six-character Utah DABS SKU. Mutually exclusive with `product_id`.
      schema:
        $ref: '#/components/schemas/DabsSku'
    ChangeStoreId:
      name: store_id
      in: query
      description: >-
        Restrict store-level inventory events to one stable API-owned store
        UUID.
      schema:
        type: string
        format: uuid
    ChangeTypes:
      name: types
      in: query
      style: form
      explode: false
      description: Comma-separated observed event types with OR semantics.
      schema:
        type: array
        maxItems: 8
        uniqueItems: true
        items:
          $ref: '#/components/schemas/ProductChangeType'
    Cursor:
      name: cursor
      in: query
      description: >-
        Signed opaque keyset cursor, valid for 15 minutes and only with the
        original resource endpoint, query, and sort. Reuse on another endpoint
        or with changed filters returns CURSOR_QUERY_MISMATCH. Follow links.next
        unchanged.
      schema:
        type: string
        maxLength: 2048
    Limit:
      name: limit
      in: query
      schema:
        type: integer
        minimum: 1
        maximum: 100
        default: 25
    IfNoneMatch:
      name: If-None-Match
      in: header
      description: Strong entity tag from an earlier response.
      schema:
        type: string
    IfModifiedSince:
      name: If-Modified-Since
      in: header
      description: HTTP-date fallback validator. ETag takes precedence.
      schema:
        type: string
  headers:
    PublicationRevision:
      description: Immutable API publication revision used for this representation.
      schema:
        type: string
        format: uuid
    ETag:
      description: >-
        Strong validator for the response representation. A new publication may
        retain the validator when this response is unchanged.
      schema:
        type: string
      example: '"v1-018f2fd0-a3d4-7d20-9c11-9482722f6b26-a91c"'
    RetryAfter:
      description: Seconds until retry or an HTTP-date.
      schema:
        type: string
    RequestId:
      description: >-
        Server-generated identifier for correlating a response with private
        operational logs.
      schema:
        type: string
        format: uuid
  schemas:
    ProductChangeSyncResponse:
      type: object
      additionalProperties: false
      required:
        - data
        - meta
        - links
      properties:
        data:
          type: array
          maxItems: 100
          items:
            $ref: '#/components/schemas/ProductChange'
        meta:
          type: object
          additionalProperties: false
          required:
            - page
            - sync
            - warnings
          properties:
            page:
              $ref: '#/components/schemas/PageMeta'
            sync:
              type: object
              additionalProperties: false
              required:
                - checkpoint
                - scope
                - order
              properties:
                checkpoint:
                  type:
                    - string
                    - 'null'
                  description: >-
                    Save only after completing the window. Null on intermediate
                    pages.
                scope:
                  type: string
                  const: observed_product_changes
                order:
                  type: string
                  const: publication_then_event
            warnings:
              type: array
              items:
                $ref: '#/components/schemas/Warning'
        links:
          $ref: '#/components/schemas/Links'
    Problem:
      type: object
      additionalProperties: false
      required:
        - type
        - title
        - status
        - detail
        - instance
        - code
        - request_id
      properties:
        type:
          type: string
          format: uri
        title:
          type: string
        status:
          type: integer
          minimum: 400
          maximum: 599
        detail:
          type: string
        instance:
          type: string
          format: uri-reference
        code:
          type: string
        request_id:
          type: string
          format: uuid
        invalid_params:
          type: array
          items:
            $ref: '#/components/schemas/InvalidParameter'
    DabsSku:
      type: string
      pattern: ^[0-9]{6}$
      examples:
        - '347210'
        - '004190'
    ProductChangeType:
      type: string
      enum:
        - product_first_observed
        - price_changed
        - status_changed
        - product_presentation_changed
        - aggregate_inventory_changed
        - store_inventory_first_observed
        - store_inventory_changed
        - catalog_presence_changed
    ProductChange:
      type: object
      additionalProperties: false
      required:
        - id
        - type
        - product
        - store
        - change
        - semantics
        - times
        - upstream_age_known
      properties:
        id:
          type: string
          format: uuid
        type:
          $ref: '#/components/schemas/ProductChangeType'
        product:
          $ref: '#/components/schemas/ProductChangeProduct'
        store:
          oneOf:
            - $ref: '#/components/schemas/ProductChangeStore'
            - type: 'null'
        change:
          type: object
          description: >-
            Type-specific immutable previous/current values. Explicit JSON nulls
            are meaningful unknown values.
          additionalProperties: true
        semantics:
          type: string
          enum:
            - first_observed_by_nektir
            - published_value_change
            - published_presentation_change
            - reported_observation_change_not_inferred_sale
            - baseline_observation_not_restock
            - source_presence_change_missing_does_not_imply_zero_inventory
        times:
          $ref: '#/components/schemas/NullableObservationTimes'
        upstream_age_known:
          type: boolean
    PageMeta:
      type: object
      additionalProperties: false
      required:
        - has_more
        - next_cursor
      properties:
        has_more:
          type: boolean
        next_cursor:
          type:
            - string
            - 'null'
        cursor_expires_at:
          type: string
          format: date-time
          description: Present only when `next_cursor` is non-null.
    Warning:
      type: object
      additionalProperties: false
      description: >-
        Machine-readable data qualification. Current codes include FIXTURE_DATA,
        INVENTORY_COVERAGE_PARTIAL, SOURCE_REFRESH_DELAYED,
        UPSTREAM_PRODUCT_UNAVAILABLE, SOURCE_SCHEMA_QUARANTINED, and
        CATALOG_BATCH_OLD.
      required:
        - code
      properties:
        code:
          type: string
          examples:
            - INVENTORY_COVERAGE_PARTIAL
    Links:
      type: object
      additionalProperties: false
      required:
        - self
        - next
      properties:
        self:
          type: string
          format: uri-reference
        next:
          type:
            - string
            - 'null'
          format: uri-reference
    InvalidParameter:
      type: object
      additionalProperties: false
      required:
        - name
        - reason
      properties:
        name:
          type: string
        reason:
          type: string
    ProductChangeProduct:
      type: object
      additionalProperties: false
      required:
        - id
        - source_ids
        - name
        - brand
      properties:
        id:
          type: string
          format: uuid
        source_ids:
          $ref: '#/components/schemas/SourceProductIds'
        name:
          type: string
          description: >-
            Consumer display title without the resolved brand or a trailing
            package dimension when one was captured in the event label.
        brand:
          type:
            - string
            - 'null'
    ProductChangeStore:
      type: object
      additionalProperties: false
      required:
        - id
        - source_ids
        - name
      properties:
        id:
          type: string
          format: uuid
        source_ids:
          type: object
          additionalProperties: false
          required:
            - inventory_store_code
          properties:
            inventory_store_code:
              $ref: '#/components/schemas/StoreInventoryCode'
        name:
          type: string
    NullableObservationTimes:
      type: object
      additionalProperties: false
      required:
        - source_updated_at
        - retrieved_at
        - published_at
      properties:
        source_updated_at:
          type:
            - string
            - 'null'
          format: date-time
        retrieved_at:
          type:
            - string
            - 'null'
          format: date-time
        published_at:
          type:
            - string
            - 'null'
          format: date-time
    SourceProductIds:
      type: object
      additionalProperties: false
      required:
        - utah_dabs_sku
      properties:
        utah_dabs_sku:
          $ref: '#/components/schemas/DabsSku'
    StoreInventoryCode:
      type: string
      pattern: ^[0-9]{4}$
      examples:
        - '0002'
  responses:
    NotModified:
      description: Representation has not changed for the supplied validator.
      headers:
        ETag:
          $ref: '#/components/headers/ETag'
        Cache-Control:
          description: Cache policy for the validated representation.
          schema:
            type: string
        X-Publication-Revision:
          $ref: '#/components/headers/PublicationRevision'
    BadRequest:
      description: Invalid parameters, incompatible scope, or cursor/query mismatch.
      headers:
        Cache-Control:
          schema:
            type: string
          example: no-store
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
    RateLimited:
      description: Public read-rate limit exceeded.
      headers:
        Cache-Control:
          schema:
            type: string
          example: no-store
        Retry-After:
          $ref: '#/components/headers/RetryAfter'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
    InternalError:
      description: >-
        An unexpected server failure. Details are withheld; report the response
        request identifier.
      headers:
        Cache-Control:
          schema:
            type: string
          example: no-store
        X-Request-ID:
          $ref: '#/components/headers/RequestId'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'
    Unavailable:
      description: >-
        The serving database is unavailable, or an export is busy or exceeds a
        configured build limit. Keep last-known-good data and honor Retry-After.
        Persistent EXPORT_UNAVAILABLE size or deadline failures need operator
        review.
      headers:
        Cache-Control:
          schema:
            type: string
          example: no-store
        Retry-After:
          $ref: '#/components/headers/RetryAfter'
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/Problem'

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.