v2.3.7: Offer conditions, order list filters & security fixes
Mercur v2.3.7 is a smaller release with one new building block and a batch of fixes.
Offers learn about conditions, so operators can define "new", "refurbished," or "used," and sellers pick one per listing.
The admin order list gets a payment status filter, server-side search in its filters, and smarter search by order number.
Two security fixes close cross-seller gaps in the vendor API and in cart promotions, and payouts no longer call the provider before a row is written.
What's New
Offer conditions
Operators define the physical conditions an offer may be listed under through /admin/offer-conditions (code, label, is_active, rank), and sellers pick an active one via condition_id when creating or updating an offer. Admin, vendor, and store offer responses expose condition.{id,code,label} and filter on condition_id. Deleting a condition in use is refused; deactivating keeps existing offers but blocks new assignments. API only for now, with createOfferConditionsWorkflow /update/delete hooks and offer_condition.* events.
Admin
- Filter order groups by payment status. The status is computed from payment collections, so
GET /admin/order-groups?payment_status=capturedmatches exactly what the list shows. - Search by the numbers operators actually see:
264,#264or#G258now match the group's display ID or any child order's display ID. - Customer, Store, and Sales channel filters search on the server, so stores with more than 1000 customers or sellers can select any of them.
Security
Cross-seller access in the vendor API
Several vendor API routes let one seller reach another seller's data: fields traversal into other sellers' members, payment details and invite tokens; product detail routes on another seller's drafts; capture of shared cart payments; and offer and inventory body IDs pointing at another seller's items or locations. All of these cross-seller authorization gaps are now closed.
Cart promotions leaking across sellers
Seller promotions are now scoped to the seller's own items on every cart refresh, not only when applied through POST /store/carts/:id/promotions. A vendor promotion without seller-specific target rules, or an automatic one, no longer discounts other sellers' items. If your storefront relied on that, it was a bug.
What's Changed
Core
- Made payouts briefly pending (breaking) –
createPayoutsnow inserts the row before calling the provider, sopayout.createdfires for a pending row. Readers that assumed every row is already sent should checkstatus. - Added an
offer_conditiontable andoffer.condition_id(seeded with a defaultnewcondition), and widened the payoutstatuscheck constraint to acceptprocessing– run migrations before upgrading.
What's Fixed
Admin & Vendor Panel
- Rebuilt the Variants table on every attribute change in Products → Create.
- Surfaced product creation errors as a toast instead of a silent 400.
- Intersected
idandseller_idfilters onGET /admin/order-groupsinstead of returning every group.
Core
- Inserted the payout row before calling the provider, used the payout id as the default
idempotency_key, and accepted theprocessingstatus in the database.
More product updates
Ready to build?
Read the release notes, then see the product – open the demo, or book a walkthrough on your terms.


