# Metrics & Reports API Instead of pulling raw orders and computing KPIs yourself, OmniCart can compute them for you: revenue, order counts, AOV, refunds, retention, channel breakdowns, and top products — consistent with what the admin dashboard shows. Prerequisite: an admin token — see [Data Access Overview](/tutorials/overview). --- ## 1. Dashboard metrics — `GET /admin/metrics` One call returns the full KPI snapshot for a date range. ```bash curl -G 'https://your-store.omnicart.cc/admin/metrics' \ -H 'Authorization: Bearer YOUR_TOKEN' \ --data-urlencode 'startDate=2026-07-01T00:00:00Z' \ --data-urlencode 'endDate=2026-07-14T23:59:59Z' \ --data-urlencode 'comparison=none' ``` **Query parameters:** | Param | Default | Notes | |-------|---------|-------| | `startDate` / `endDate` | last 30 days | ISO timestamps recommended. Max range: **365 days**. | | `comparison` | `previous` | `previous` (prior period), `year_ago`, or `none`. Use `none` for scheduled pulls unless you want change percentages. | | `salesChannel` | all | Scope to one store/channel by ID. | **Response structure (abridged):** ```json { "success": true, "metrics": { "summary": { "cards": [ { "id": "total_revenue", "title": "Total Revenue", "value": 48210.55, "format": "currency", "changePercentage": 12.4, "trend": "up" }, { "id": "total_orders", "title": "Total Orders", "value": 1284, "format": "number" } ] }, "trends": [ "..." ], "breakdowns": { "salesChannels": [ { "channelId": "...", "channelName": "...", "orders": 512, "revenue": 19882.12, "averageOrderValue": 38.83 } ], "products": [ { "productId": "...", "title": "...", "quantity": 431, "revenue": 12931.69 } ] }, "section_errors": {} } } ``` **Card IDs you can rely on** in `metrics.summary.cards[]`: | `id` | Meaning | Format | |------|---------|--------| | `total_revenue` | Revenue for the period | currency | | `total_orders` | Order count | number | | `average_order_value` | AOV | currency | | `total_refunded` / `refund_rate` / `refund_count` | Refund figures | currency / % / number | | `new_customers` / `returning_customers` | Customer counts | number | | `customer_retention_rate` | Returning-customer rate | percentage | | `revenue_per_customer` | Revenue ÷ unique customers | currency | | `unfulfilled_paid_orders` | Paid orders not yet fulfilled | number | **Two things scheduled consumers must handle:** 1. **`section_errors` — partial results return HTTP 200.** If one section fails to compute, the response still succeeds and the failing section is listed in `section_errors` (its data will be missing/null). Always check it before trusting a snapshot. 2. **Freshness:** results are cached server-side for up to ~5 minutes. Fine for dashboards; if you reconcile against raw orders, expect small timing differences at the cache boundary. Rate limit: 60 requests/minute per user where enforced (deployment-dependent — design to the budget and handle 429s, but don't be surprised if you never see one). --- ## 2. Batch reports — `POST /admin/metrics/batch` Fetch multiple report types or multiple date ranges in one round trip. The **50-requests-per-batch maximum is always enforced**; the 5-batches/minute rate limit applies where rate limiting is enabled in your deployment. ```bash curl -X POST 'https://your-store.omnicart.cc/admin/metrics/batch' \ -H 'Authorization: Bearer YOUR_TOKEN' \ -H 'Content-Type: application/json' \ -d '{ "requests": [ { "id": "revenue-last-7d", "type": "dashboard", "filters": { "range": { "start": "2026-07-14T00:00:00Z", "end": "2026-07-21T00:00:00Z" }, "comparison": "none" } }, { "id": "revenue-last-30d", "type": "dashboard", "filters": { "range": { "start": "2026-06-21T00:00:00Z", "end": "2026-07-21T00:00:00Z" }, "comparison": "none" } } ] }' ``` Each request has a caller-chosen `id` (echoed back), a `type` — `dashboard`, `paid_acquisition`, `order_report`, or `fulfillment_report` — and type-specific `filters`. The response returns per-request results plus a summary: ```json { "results": [ { "id": "revenue-last-7d", "success": true, "data": { "..." : "..." }, "cacheHit": true, "executionTimeMs": 12 } ], "summary": { "total": 2, "successful": 2, "failed": 0, "cacheHitRate": 50 } } ``` Check `success` per item — one failed request does not fail the batch. --- ## 3. Custom metric definitions — `/admin/metrics-registry` The registry holds named metric formulas (system-provided and your own), e.g. `net_revenue = SUM({order_total}) - SUM({refund_total})`. **Discover available metrics and their IDs:** ```bash curl -G 'https://your-store.omnicart.cc/admin/metrics-registry/definitions' \ -H 'Authorization: Bearer YOUR_TOKEN' \ --data-urlencode 'category=revenue' ``` Returns `{ "metrics": [...], "count": n }` — each definition has an `id`, `name` (e.g. `total_revenue`, `net_revenue`, `average_order_value`, `completed_orders`), `category`, and `formula`. Browse available formula building blocks with `GET /admin/metrics-registry/placeholders`. **Execute a formula:** ```bash curl -X POST 'https://your-store.omnicart.cc/admin/metrics-registry/execute' \ -H 'Authorization: Bearer YOUR_TOKEN' \ -H 'Content-Type: application/json' \ -d '{ "metric_id": "metdef_01...", "context": { "order_total": [19.99, 45.50], "refund_total": [19.99] } }' ``` Two important notes: - `metric_id` is the definition's **`id`**, not its `name` — look it up via the definitions endpoint first. - `execute` evaluates the formula against the **values you supply in `context`**; it does not query your order history by date range. For date-ranged KPIs, use `GET /admin/metrics` or the batch endpoint above. The registry is for defining and computing custom formulas over data you've already aggregated. --- ## Recommended pattern: daily KPI snapshot 1. Once per day (after your business day closes), call `GET /admin/metrics` with an explicit ISO range for that day and `comparison=none`. 2. Extract the cards you need by `id` (`total_revenue`, `total_orders`, `average_order_value`, `total_refunded`). 3. Check `section_errors` is empty; retry once after a minute if not. 4. Append the row to your warehouse/spreadsheet — this becomes the fact table your BI tool reads. See [Looker & Looker Studio](/tutorials/looker).