Reports
Discover, compare, and rank read-only commercial report rollups with key and user access checked at request time.
Reports are for aggregate sales, purchasing, and open-order views. Use them when a workflow needs a rollup, dashboard, or comparison table, not individual record detail.
Endpoints
| Endpoint | Use it for |
|---|---|
GET /reports | List report keys, parameters, dimensions, measures, required scope, and whether this key can run each report. |
GET /reports/{reportKey} | Run one allowed report with documented parameters and offset pagination. |
Report routes require reports:read plus the acting user's live ShelfCycle permissions. GET /me also reports effectiveCapabilities.reports.available so clients can check available report keys before showing report actions.
Discover reports
Call the catalog before running a report. The catalog is the best source for labels, accepted parameters, dimensions, measures, and per-key availability.
curl "$SHELFCYCLE_API_BASE_URL/reports" \
-H "Authorization: Bearer $SHELFCYCLE_API_KEY" \
-H "X-ShelfCycle-Client: Revenue dashboard"
{
"data": {
"reports": [
{
"key": "sales-summary",
"title": "Sales summary",
"description": "Sales rollups by customer, product, salesperson, supplier, or month.",
"params": [
{ "name": "groupBy", "required": true, "description": "One or two dimensions." },
{ "name": "startDate", "required": true, "description": "YYYY-MM-DD in the org timezone." },
{ "name": "endDate", "required": true, "description": "YYYY-MM-DD in the org timezone." },
{ "name": "comparisonStartDate", "required": false, "description": "Start of an optional comparison window." },
{ "name": "comparisonEndDate", "required": false, "description": "End of an optional comparison window." }
],
"dimensions": ["customer", "productFamily", "productCode", "salesPerson", "supplier", "month"],
"measures": ["salesCents", "productCostCents", "orderCostsCents", "totalCostCents", "gpCents", "gpPct"],
"requiredScope": "reports:read",
"allowedForThisKey": true
}
]
}
}
If allowedForThisKey is false, do not run that report with the same key.
Run a report
curl "$SHELFCYCLE_API_BASE_URL/reports/sales-summary?groupBy=customer&startDate=2026-04-01&endDate=2026-06-30&comparisonStartDate=2026-01-01&comparisonEndDate=2026-03-31&dateField=invoiceDate&sortBy=salesDelta&sortDirection=desc&limit=50" \
-H "Authorization: Bearer $SHELFCYCLE_API_KEY" \
-H "X-ShelfCycle-Client: Revenue dashboard"
Report responses include report metadata, normalized params, basis notes, rows, complete filtered-population totals, and pagination metadata. Rows always include groupId, bucketKey, and groupName; two-level groupings also include group2Id, group2Key, and group2Name.
Money values are cents-as-string in the org base currency. Keep them as integer strings or decimal-safe values in your application. Do not convert cents to JavaScript floating dollars for comparisons.
Compare two periods
Add comparisonStartDate and comparisonEndDate together to compare the primary window with another bounded period. The windows can be adjacent, overlapping, equal in length, or different in length. Each window can span up to 366 days, with up to 732 combined days.
When comparison dates are present, sales and purchase rows include:
comparisonmeasures for the comparison windowdeltascalculated as primary minus comparisoncomparisonClassificationwithnew,lost, orretainedactivity
Use comparisonClassification to focus on groups active only in the primary period, only in the comparison period, or in both. Classification follows recorded activity, so zero-dollar and credit activity are not mistaken for inactivity.
Sorting happens across the complete filtered population before limit and offset are applied. Sales summaries can sort by sales, gross profit, comparison values, or their changes. Purchase summaries can sort by spend, comparison spend, or spend change. Use sortDirection=desc for the largest increases and sortDirection=asc for the largest declines.
data.totals covers the filtered population before pagination. meta.rankingComplete confirms that ranking considered that population, while meta.rowsCoverFullPopulation tells you whether the returned rows contain the complete filtered result. This lets a workflow make a top-ranked claim without treating one page as a complete list.
Available reports
| Report key | What it returns |
|---|---|
sales-summary | Sales, cost, gross profit, and gross profit percent by one or two dimensions: customer, product family, product code, salesperson, supplier, or month. |
purchase-summary | Material purchase-order spend by supplier, product code, or product family. |
open-sales-orders | Current open sales-order value by status or customer. |
Parameter notes
sales-summary accepts startDate and endDate in YYYY-MM-DD format and dateField as invoiceDate, shipDate, or orderDate. It supports one or two grouping dimensions. For period comparisons, use customer, product family, product code, salesperson, or supplier dimensions. Month remains available for single-period rollups.
purchase-summary uses purchase-order created dates and supports supplier, product-code, or product-family comparisons. Its spend is material purchase-order item amount only. It excludes landed costs, standalone purchase-order cost rows, AP cash payments, quantity, and unit-cost measures.
open-sales-orders uses current sales orders in confirmed and shipped states. includeDraft=true adds draft orders. It returns open sell value only, without cost or margin.
Reports paginate with limit and offset. Finder and reference-directory routes use their own documented pagination.
Reports are read-only rollups. Use detail endpoints for selected records, not reports, when a workflow needs record-specific fields, notes, documents, or write readiness.