Supercommerce API Docs
Admin API

Product Sold Metrics Module — Admin surface

Admin-facing HTTP surface for the per-product "units sold last month" metric: a monthly BullMQ recompute over confirmed orders, a manual re-trigger, and admin-configured display-override rules.

Admin-facing HTTP surface for the per-product "units sold last month" metric: a monthly BullMQ recompute over confirmed orders, a manual re-trigger, and admin-configured rules that can override what count is actually shown to customers.

The per-product numbers themselves are not served from a dedicated list/report endpoint here — they're embedded directly into the existing GET /admin/products, GET /admin/products/:id/detail, and GET store/products/:slug responses (see Catalog). This module owns only: the monthly compute job, the manual refresh trigger, the run-status pointer, and the sold_last_month settings group (see Settings).

Source: api-modules/product-sold-metrics/src/controllers/admin-product-sold-metrics.controller.ts.


"Sold" criteria

A unit counts as sold when its order has order.status = "confirmed" and was placedAt within the target calendar month — independent of payment_status. This correctly includes COD orders (which stay payment_status = pending until delivery) and excludes cancelled or still-pending-payment orders.

The recompute is a full replace of that month's rows (not an incremental upsert): every existing row for the period is deleted and re-inserted from a fresh aggregation, so a product whose confirmed units dropped to 0 since the last run (e.g. its orders got cancelled) correctly loses its row rather than keeping a stale count.

Conventions

Authentication & authorization

Both endpoints require a Better-Auth admin bearer session and the productSoldMetrics permission (view for reads, refresh for the manual trigger). The productSoldMetrics resource is granted to the built-in superAdmin role; narrower dynamic roles must be granted it explicitly. See Admin RBAC.

Response envelope

{
  "data": { /* payload */ },
  "message": "Success",
  "statusCode": 200
}

Endpoints

GET /admin/product-sold-metrics/status

Returns the run-state pointer: which calendar month is currently authoritative and when it was computed.

Response fields (data object)

FieldTypeDescription
periodstring | nullFirst-of-month date the currently-served numbers cover (e.g. "2026-06-01"), or null if the job has never run
computedAtstring | nullISO datetime of the last successful recompute, or null if never computed

POST /admin/product-sold-metrics/refresh

Enqueues an immediate recompute of last month's per-product sold counts, instead of waiting for the monthly schedule (00:30 UTC on the 1st).

Requires productSoldMetrics: ["refresh"].

The recompute runs in the background on the worker, not in this request. The handler enqueues a one-off product-sold-metrics-monthly-refresh job (fixed jobId product-sold-metrics-manual-refresh, so rapid repeat calls dedup to a single in-flight run) onto the product-sold-metrics BullMQ queue the cron uses, then returns immediately. Poll GET /admin/product-sold-metrics/status afterwards — once the worker finishes, computedAt advances.

Response 200

{ "data": { "enqueued": true } }

Settings — display-override rules

The sold_last_month settings group (store scope; see Settings) holds:

KeyPublicPurpose
enabledyesWhether the storefront shows the count at all. Read via the anonymous GET /store/settings/sold_last_month endpoint.
render_rulesnoThe display-override rule list. Never leaves the admin API.

render_rules is an ordered list of { operator, threshold, displayValue }. operator is one of lt, lte, eq, gt, gte. Rules are evaluated top to bottom — first match wins — and the real count is shown unchanged when no rule matches. Example: a rule { operator: "gte", threshold: 151, displayValue: 250 } means "whenever the actual count is 151 or higher, show 250 instead."

Admin surfaces (the product list column and detail page) always show both the real count and the display value, regardless of enabled — that flag only gates the storefront.


  • Catalog — owns the actual product endpoints this module's numbers are embedded into (Catalog). Consumed via an optional port (PRODUCT_SOLD_METRIC_PORT); removing this module drops the field from those responses entirely.
  • Settings — the sold_last_month group's admin UI (a generic settings-registry page) and the public storefront settings read (Settings).
  • Analytics — the precedent for this module's BullMQ refresh-job pattern and manual-trigger dedup (Analytics).

On this page