Skip to main content
Resolve a pending product change from your own code, for example in a custom review tool or an automated approval rule. Each resolution has its own workflow, so the status update, the product write, and the event always happen together.

Before you begin

You need the following in place:
  • A Mercur server with @mercurjs/core installed through withMercur()
  • A change in pending status. Changes stay pending only while the product_request feature flag is on, the default

Review and resolve a change

Find the pending change, then confirm or decline it.
1

Find pending changes

List the pending changes on a product with their actions, so a reviewer can see what each one does.
Each action’s details holds the proposed value and the previous one, as described in Change actions.
2

Confirm the change

confirmProductChangeWorkflow sets the changes to confirmed, applies their actions to the product, and emits product-change.confirmed.
src/api/admin/custom/changes/[id]/confirm/route.ts
The input takes an ids array. Pass internal_note or external_note to overwrite the change’s notes as you confirm it.
3

Or decline it

rejectProductChangeWorkflow sets one change to declined and leaves the product untouched. Give the seller a reason in declined_reason.
The workflow emits product-change.declined with the change id.

Cancel a change

Cancel a change when it should be withdrawn rather than judged, for example when a seller retracts their own edit. Canceling frees the author to stage a new change on the product.
The workflow sets canceled_by and canceled_at, then emits product-change.canceled.

Confirm several changes at once

confirmProductChangeWorkflow loads every id in ids before it writes anything. If one id doesn’t exist, it throws a NOT_FOUND error. If one change isn’t pending, it throws NOT_ALLOWED, and none of the changes are confirmed.

Handle a failed apply

Applying actions runs Medusa’s product workflows inside the confirm workflow. If one of them fails, for example because a variant was already deleted, the workflow compensates: it restores the change to pending and clears confirmed_by and confirmed_at. Fix the cause, then confirm again.

Run your own logic on a resolution

Each resolution workflow has a hook that receives the change ids and the additional_data you passed in:
  • confirmProductChangeWorkflow: productChangeConfirmed, with { ids, additional_data }
  • rejectProductChangeWorkflow: productChangeRejected, with { id, additional_data }
  • cancelProductChangeWorkflow: productChangeCanceled, with { id, additional_data }
Use a hook when your logic must succeed or fail together with the resolution. For side effects that can run later, such as an email to the seller, subscribe to the events listed in the Events reference.

Next steps