Reporting — Products
Returns the aggregate statistics that power the Bagisto admin Reporting → Products screen — sold quantities, wishlist additions, top sellers, review counts, visit counts and search-term analytics.
| Stats endpoint | GET /api/admin/reporting/products |
| View Details endpoint | GET /api/admin/reporting/products/view |
| Export endpoint | GET /api/admin/reporting/products/export |
| Returns | A JSON array with a single element: [ { entity, type, dateRange, statistics } ] (entity is always "products") |
All admin endpoints require an admin Bearer token — see Authentication.
Understanding type — the Products report is eight separate calls
This is the most important thing to understand about this API.
The Products reporting screen is not one response. Each panel is a separate request selected with the ?type= query parameter. A single call returns one report, and the statistics payload changes shape per type — sometimes an object (the chart reports), sometimes a flat array (the ranked-list reports) — so always branch on type when consuming it.
total-sold-quantities is the default — if you omit ?type=, you get the sold-quantities chart.
Query parameters
| Param | Type | Required | Description |
|---|---|---|---|
type | enum | No | One of the eight values listed below. Defaults to total-sold-quantities. An unknown value returns 400 (invalid-type). |
start | date (YYYY-MM-DD) | No | Lower bound of the reporting window. Defaults to 30 days ago. |
end | date (YYYY-MM-DD) | No | Upper bound. Defaults to today. |
channel | string | No | Channel code to scope the figures to a single channel. Defaults to all channels. |
start / end drive both the figures and the previous baseline used for each progress percentage — the previous period is the same-length window immediately before start.
Response envelope
The endpoint always returns a single-element array: [ { entity, type, dateRange, statistics } ].
entity— always"products".type— echoes back the requested report.dateRange— an object{ previous, current }with a human-readable label for each window (e.g.{ "previous": "10 Apr 2026 - 10 May 2026", "current": "10 May 2026 - 09 Jun 2026" }).statistics— an object or array whose shape depends ontype(documented below).
Response shapes by type
Figures with a previous / current / progress shape are period comparisons: current is the chosen window, previous is the preceding window of equal length, and progress is the percentage change (can be negative).
type | statistics is | Shape |
|---|---|---|
total-sold-quantities | object | { quantities: { previous, current, progress }, over_time: { previous: [{label,total}], current: [{label,total}] } } |
total-products-added-to-wishlist | object | { wishlist: { previous, current, progress }, over_time: { previous: [{label,total}], current: [{label,total}] } } |
top-selling-products-by-revenue | array | rows of { id, name, price, formatted_price, revenue, formatted_revenue, progress, images: [{id,type,path,product_id,position,url}] } |
top-selling-products-by-quantity | array | rows of { id, name, price, formatted_price, total_qty_ordered, progress, images: [{id,type,path,product_id,position,url}] } |
products-with-most-reviews | array | rows of { product_id, product_name, reviews, progress } |
products-with-most-visits | array | rows of { visitable_id, name, visits, progress } |
last-search-terms | array | rows of { id, term, results, uses, channel_id, locale } |
top-search-terms | array | rows of { id, term, results, uses, channel_id, locale } |
total-sold-quantities
| Key | Shape | Meaning |
|---|---|---|
quantities | { previous, current, progress } | Total units sold in the window vs. the previous window. |
over_time | { previous: [{label,total}], current: [{label,total}] } | Two per-day series (previous and current windows) for the chart line; total is units sold per bucket. |
total-products-added-to-wishlist
| Key | Shape | Meaning |
|---|---|---|
wishlist | { previous, current, progress } | Wishlist additions in the window vs. the previous window. |
over_time | { previous: [{label,total}], current: [{label,total}] } | Two per-day series for the chart line; total is additions per bucket. |
top-selling-products-by-revenue
statistics is an array of product rows. Each row: id, name, price (may be null), formatted_price, revenue, formatted_revenue, progress, and images (array of { id, type, path, product_id, position, url } — empty when the product has no image).
top-selling-products-by-quantity
statistics is an array of product rows. Each row: id, name, price, formatted_price, total_qty_ordered, progress, and images (array of { id, type, path, product_id, position, url }).
products-with-most-reviews
statistics is an array. Each row: product_id, product_name, reviews (count in the window), progress.
products-with-most-visits
statistics is an array. Each row: visitable_id, name, visits, progress. Visit figures depend on the Bagisto visitor/analytics tables being populated; on a fresh store this report is empty.
last-search-terms
statistics is an array of the most recent storefront searches. Each row: id, term, results (matches returned), uses (times searched), channel_id, locale.
top-search-terms
statistics is an array of the most-used storefront searches — same row shape as last-search-terms (id, term, results, uses, channel_id, locale), ranked by uses. This report has no View Details (table) form — it is stats-only.
View Details (table form)
GET /api/admin/reporting/products/view returns the same reports in a detailed table form — the full list behind a panel's View Details link. It honors the same type values as the stats endpoint (with the exception of top-search-terms, which has no table form). Here statistics is always an object with two keys:
columns— an ordered list of{ key, label }describing each table column.records— the row data; each record is keyed by the columnkeyvalues (records may carry extra fields beyond the displayed columns, e.g. the rawrevenue/imagesalongside the formatted display values).
This is the expanded, row-by-row view; the summary stats endpoint returns the rolled-up headline figures instead.
Export (CSV)
GET /api/admin/reporting/products/export streams the same detailed table as a csv, xls or xlsx attachment (the Export button). The header row is built from the column labels, followed by one line per record. Send the Accept header matching the requested format and save the response to a file.
?format= accepts csv (the default), xls and xlsx — any other value returns HTTP 422. Send an Accept header matching the format: text/csv, application/vnd.ms-excel or application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.
Both View Details and Export require only authentication; reporting has no permission gate.
Errors
| Condition | HTTP | Body |
|---|---|---|
| Missing / invalid Bearer token | 401 | { "message": "Unauthenticated.", "error": "unauthenticated" } |
Unknown type value | 400 | { ... "Invalid reporting stat type." } |
format other than csv on Export | 422 | { ... unsupported export format } |
See also
- Reporting — Products (GraphQL) — same data over the
statsAdminReportingProductsquery. - Dashboard Statistics — the at-a-glance dashboard figures.

