v2.3.7
mercurjs/mercurv2.3.7Oct 8, 2026by github-actions[bot]
Upgrading?
AI Summary
A smaller release introducing 'Offer Conditions' for listing states, enhancing the Admin Order List with server-side search and payment status filtering, and addressing security vulnerabilities.
Key Highlights
- Introduced 'Offer Conditions' to define listing states like 'new', 'refurbished', or 'used'.
- Enhanced Admin Order List with server-side search for customers, sellers, and sales channels.
- Fixed security vulnerabilities in the vendor API and seller promotions to prevent cross-seller authorization issues.
- Updated payout logic to insert rows before calling the provider to ensure proper status tracking.
Breaking Changes
- Migrations are required: the `offer_condition` table is added and the `payout.status` constraint is widened.
- Payouts are briefly `pending` because the row is inserted before the provider is called.
- Seller promotions are now strictly scoped to the seller's own items, which may break existing logic relying on broader application.
New Features
- Offer Conditions management via `/admin/offer-conditions`.
- Payment status filter in the Admin Order List.
- Smart order search matching display IDs (e.g., `#264`).
- Server-side filtering for customers, sellers, and sales channels.
Full Release Notes
# Mercur v2.3.7
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.
## ⚠️ Before you upgrade
- **Run migrations** — the offer module adds an `offer_condition` table and
`offer.condition_id` (seeded with a default `new` condition), and the payout
module widens the `payout.status` check constraint to accept `processing`
(#1645, #1641).
- **Payouts are briefly `pending`.** `createPayouts` now inserts the row
before calling the provider, so `payout.created` fires for a pending row and
readers that assumed every row is already sent should check `status` (#1641).
- **Seller promotions are scoped on every cart refresh.** 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 (#1648).
## ✨ Highlights
### 🏷️ 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. (#1645)
### 📋 Admin order list
- Filter order groups by **payment status**. The status is computed from
payment collections, so `GET /admin/order-groups?payment_status=captured`
matches exactly what the list shows (#1639).
- Search by the numbers operators actually see: `264`, `#264` or `#G258` now
match the group's display id or any child order's display id (#1638).
- Customer, Store and Sales channel filters search on the server, so stores
with more than 1000 customers or sellers can select any of them (#1640).
## 🔒 Security
Both issues below were reported privately by @gregbarajas, with clean
end-to-end reproductions on a v2.3.6 starter that made the fixes
straightforward. Thank you, Greg!
- Close cross-seller authorization gaps in the vendor API: `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 / inventory body ids pointing at another seller's items or
locations (GHSA-mhch-gq7f-v5p7, #1649).
- Keep seller promotions scoped to the seller's own items on every cart
refresh, not only when applied through `POST /store/carts/:id/promotions`
(GHSA-w4vq-6jvh-cfpg, #1648).
## 🐛 Fixes
- Insert the payout row before calling the provider, use the payout id as the
default `idempotency_key`, and accept the `processing` status in the
database (#1641).
- Intersect `id` and `seller_id` filters on `GET /admin/order-groups` instead
of returning every group (#1637).
- Rebuild the Variants table on every attribute change in Products → Create in
both panels, and surface create errors as a toast instead of a silent 400
(#1650).
**Full Changelog**: https://github.com/mercurjs/mercur/compare/v2.3.6...v2.3.7
Related Repositories
openclaw/openclaw★ 392,725
The AI that really does things. Any OS. Any Platform. The lobster way. 🦞
nilbuild/developer-roadmap★ 370,103
Interactive roadmaps, guides and other educational content to help developers grow in their careers.
morluto/rea★ 361,094
Reverse engineer anything with agents, from app behavior down to native binaries.
anomalyco/opencode★ 219,904
The open source coding agent.
n8n-io/n8n★ 208,287
Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.