Skip to main content
A product change is one reviewable edit to one product. Because every seller sells against the same shared product, a seller’s edit can’t take effect the moment it’s made. Mercur stores the edit as a ProductChange with its actions, holds it for review, and applies it only on confirmation. The same records double as the product’s history.

The product change record

A ProductChange (id prefix prodch) points at its product through product_id and carries a status from the ProductChangeStatus enum. It owns one or more ProductChangeAction rows in actions, one per operation it will apply. The change is the unit you review. The actions are what gets written. Each resolution stamps an actor and a time on the record:
  • Staging: created_by
  • Confirm: confirmed_by, confirmed_at
  • Decline: declined_by, declined_at, declined_reason
  • Cancel: canceled_by, canceled_at
The actor fields are plain text. Vendor routes write the seller id (sel_…) into created_by, and admin routes write the operator’s user id. Two notes travel with the change: internal_note for operators and external_note for the seller.
The service call loads one change with its actions. To read a product’s full history, use the product.changes link instead, covered in Links.

How an edit is staged

Seller edits reach the pipeline through four edit workflows. Each one loads the current product, compares your input against it, and passes only the differences to stageProductChangeWorkflow:
  • productEditUpdateProductWorkflow: product fields and status, as UPDATE and STATUS_CHANGE actions
  • productEditUpdateVariantsWorkflow: variant add, update, and remove operations, as VARIANT_* actions
  • productEditUpdateAttributesWorkflow: attribute add, update, and remove, as ATTRIBUTE_* actions
  • productEditDeleteProductWorkflow: a single PRODUCT_DELETE action
stageProductChangeWorkflow creates the pending change, creates its actions, emits product-change.created, and then runs autoConfirmProductChangeWorkflow. Whether the change confirms in that same run is covered in Status & auto-confirm.

One open change per author

The edit workflows and createProductChangeWorkflow refuse to stage a change when the same author already has a pending change on that product. The check is scoped by created_by, so two different sellers can each have one open change on the same shared product. When created_by is missing, the check covers every pending change on the product.
stageProductChangeWorkflow doesn’t run this check. Call it directly only when you’ve handled conflicts yourself, or prefer an edit workflow.
The conflict surfaces as a NOT_ALLOWED error: “There is already an active update request for this product. Only one request can be active at a time.” The author resolves it by canceling the open change or waiting for an operator to resolve it.

Audit changes

Some events change a product without a review, yet still belong in its history. recordProductAuditChangeWorkflow stores them as changes created already confirmed, with every action marked applied, so confirming never replays them. Mercur’s product workflows call it in four places: The PRODUCT_ADD record does real work: its created_by is the seller who submitted the product, and the vendor API reads it to tell which products a seller created.
Operator edits through the admin product update route run Medusa’s updateProductsWorkflow directly and don’t create a change. The pipeline governs seller edits.