Catalog Sync
What publication-scoped syncing changes for your Violet API integration: which products you receive, the product lifecycle, and webhook behavior.
This page is for developers building against the Violet API for channels configured as a Shopify sales channel. It assumes the concepts on Sales Channel Publishing on Shopify.
What changes for your integration
Your catalog for a Shopify merchant is now the set of products that merchant has published to your channel, not their whole store. Three consequences worth designing for:
Catalog size is merchant-controlled and can change without warning. A merchant can unpublish a hundred products in one bulk action. Your integration should handle the catalog shrinking as a normal event, not an error condition.
A newly connected merchant may sync zero products. Products are not published to a new channel automatically. Until the merchant publishes some, their catalog is legitimately empty. Do not treat an empty catalog after connection as a failed sync.
Unpublishing is an update, not a deletion. The Offer stays exactly where it is (same id, same data, same SKUs) with its
publishing_statusset toNOT_PUBLISHED. Read that field to know whether an Offer belongs in your catalog. See Webhooks below.
Everything else (order submission, inventory, pricing, refunds, the shape of the Offer and SKU models) is unchanged.
Which products you receive
A product appears in your catalog only when all of the following are true:
The merchant has published it to your channel in Shopify.
Its Shopify status is Active.
It is not excluded by the channel's existing catalog rules: collection filters, excluded collections, excluded tags, or excluded vendors. Publication filtering is applied in addition to these rules, not instead of them.
Publication filtering is applied consistently on every path that reads products: the product count, the paged catalog sync, the bulk catalog sync, the per-product webhook sync, and the direct product sync API. There is no route through which an unpublished product can enter your catalog.
Product lifecycle
Publishes a product to your channel
Fetches the product and creates or republishes the Offer
publishing_status: PUBLISHED
OFFER_ADDED for a newly created Offer; OFFER_UPDATED and OFFER_ADDED when republishing one that already existed
Edits a published product
Re-fetches and updates the Offer
Offer updated
OFFER_UPDATED, when there are material changes
Unpublishes the product from your channel
Withdraws the Offer from your catalog
publishing_status: NOT_PUBLISHED. status, available, visible, and SKU statuses are unchanged
OFFER_UPDATED and OFFER_REMOVED
Deletes the product in Shopify
Archives the Offer
status: ARCHIVED, available: false, visible: false, every SKU status: ARCHIVED
OFFER_UPDATED
Re-publishes a previously unpublished product
Re-fetches and republishes the Offer
publishing_status: PUBLISHED again, same Offer id
OFFER_UPDATED and OFFER_ADDED
Note the difference between the middle two rows. Unpublishing from your channel is neither an archive nor a deletion. It is an update to one field. The product is still active and selling in the merchant's own store; only its membership of your catalog changed, so its status and availability are left untouched. A product actually deleted in Shopify still archives, because it genuinely is gone.
Publish and unpublish are event-driven. In normal operation the catalog reflects a merchant's change within seconds, though delivery is not instantaneous and should not be relied on as synchronous.
Webhooks
The event name is delivered in the X-Violet-Topic header. The request body is the Offer itself. For the full offer event reference, see Offer Webhooks.
Unpublishing is an update, not a deletion
When a merchant unpublishes a product from your channel, Violet sets the Offer's publishing_status to NOT_PUBLISHED and sends both OFFER_UPDATED and OFFER_REMOVED.
Despite the event name, nothing is deleted. The Offer keeps its id, its data, and its SKUs; only the publishing status changed. That is what allows a re-publish to restore the same Offer rather than create a new one. (OFFER_DELETED is a separate event, for Offers that are genuinely removed.)
publishing_status is the field that tells you whether an Offer belongs in your catalog. status and available describe the product in the merchant's own store, and an unpublished product is often still AVAILABLE there because it is still selling on their other channels. Both values are accurate; they answer different questions.
The two events are delivered independently and may arrive in either order, so don't depend on the sequence; publishing_status is correct in both.
Other webhook behavior
Offers you never received stay silent. If an Offer was never published to your app, no webhook is sent when it changes. This matches existing Violet behavior.
OFFER_UPDATEDis suppressed when nothing material changed. A re-sync that produces an identical Offer does not generate an event.Relay channels receive additional events. Channels on the Relay plan also receive
RELAY_OFFER_UPDATEDwhen a product is published or edited, andRELAY_OFFER_REMOVEDwhen it is unpublished, delivered directly from the sync layer.Your channel's catalog rules still apply. If a product is withheld by a collection, tag, or vendor rule (or if offers for that merchant are configured not to publish automatically), ticking the channel in Shopify does not override that. Channel membership and Violet publishing are separate gates, and a product must clear both.
Reconciliation
Publication changes are delivered by webhook. If your integration needs to confirm the current state of a merchant's catalog (after downtime on your side, for example), re-read the catalog through the standard Violet catalog endpoints. The result is already scoped to the merchant's published set.
Known limitation. Violet's scheduled catalog validation checks whether products still exist and whether they are Draft or Archived in Shopify, but it does not currently re-verify publication membership. If a merchant unpublishes a product during an extended interruption in webhook delivery, that Offer can remain active in Violet until the product is next modified. If accurate withdrawal is critical to your integration, periodically reconcile against the catalog endpoints.
Testing your integration
On a Shopify development store connected to your channel:
Publish a product to your channel and confirm you receive
OFFER_ADDED.Edit the product's title and confirm you receive
OFFER_UPDATED.Unpublish the product. Confirm you receive
OFFER_REMOVEDwithpublishing_status: NOT_PUBLISHED, and that your integration withdraws it. Note thatstatuswill still readAVAILABLE; the product is still selling in the merchant's store.Re-publish it and confirm it returns with the same Offer id and
publishing_status: PUBLISHED.Confirm a product you have never published to the channel never reaches your catalog.
Last updated
Was this helpful?