GET /v1/analytics returns the figures the dashboard home page shows for a period: ten KPIs, each with its value for a comparison period and the change, and eight chart series. Use it for client reports or a BI export instead of rebuilding the numbers from GET /v1/orders. The API and the dashboard share the same definitions and the same cache, so for the same period they show the same numbers. What each figure means for the merchant is explained on the Analytics page of the merchant docs.
The API always counts all traffic: store pages and landing pages together. The dashboard's traffic filter (landing pages only, or the store only) has no equivalent here.
Before you start
The key needs
analytics:read. Keys created from the dashboard (Settings → API,/dashboard/api) carry it since v1.7. Scopes are frozen when a key is created, so an older key answers403 forbiddenwith "Missing scope: analytics:read": create a new key from the dashboard. A key created throughPOST /v1/keysonly gets the scopes held by the key that created it.Personal keys need a store on an active Enterprise plan. An installed app's token is not bound to Enterprise, but it needs
analytics:readamong the scopes the merchant approved. See Introduction.Revenue, profit and average order value, and the
revenuevalues inside the charts, are sent only when the key belongs to the store owner's account. Otherwise those fields are missing from the answer: they are not set to0ornull.
Scope | Description |
| Read store analytics and KPIs. Included in merchant keys created from v1.7 on; an older key needs a new key. |
GET /v1/analytics
The report for one period.
Auth: platform key with analytics:read.
Query parameters
Param | Type | Default | Notes |
| string |
|
|
|
| none | First day. Required with |
|
| none | Last day. Required with |
Periods
| Period | Compared with |
|
| Today | Yesterday |
|
| Yesterday | The day before |
|
| Today and the 6 days before | The 7 days before those |
|
| Today and the 29 days before | The 30 days before those |
|
| The 1st to the last day of the current month | The whole previous month |
|
| The whole previous month | The month before it |
|
| 1 January to 31 December of the current year | The whole previous year |
|
|
| The same number of days just before |
|
For custom, group_by is hour when to is from or the next day, day when to is at most 90 days after from, and month beyond that. this_month and this_year run to the end of the month or the year, so they compare the days so far with a whole previous month or year.
The report is cached for 120 seconds per store and period, and the dashboard reads the same cache. A call can return figures up to two minutes old, and calls inside that window get the same numbers.
Request
curl 'https://api.dzbuild.app/v1/analytics?range=7d' \ -H "Authorization: Bearer $DZ_KEY"
A custom period:
curl 'https://api.dzbuild.app/v1/analytics?range=custom&from=2026-09-01&to=2026-09-30' \ -H "Authorization: Bearer $DZ_KEY"
Response 200
The answer for range=7d on 6 October 2026, to a key created by the store owner. The time series and the lists are cut to their first entries.
{
"data": {
"period": {
"from": "2026-09-30 00:00:00",
"to": "2026-10-06 23:59:59",
"prev_from": "2026-09-23 00:00:00",
"prev_to": "2026-09-29 23:59:59",
"label": "7d",
"group_by": "day"
},
"kpis": {
"total_orders": { "value": 48, "change": 20, "previous": 40 },
"delivered_orders": { "value": 31, "change": 7, "previous": 29 },
"cancelled_orders": { "value": 6, "change": -25, "previous": 8 },
"total_revenue": { "value": 186000, "change": 8, "previous": 172000 },
"total_profit": { "value": 61500, "change": 6, "previous": 58000 },
"avg_order_value": { "value": 4350, "change": -1, "previous": 4400 },
"total_visitors": { "value": 1520, "change": 17, "previous": 1300 },
"page_views": { "value": 4810, "change": 17, "previous": 4100 },
"conversion_rate": { "value": 3.2, "change": 3, "previous": 3.1 },
"new_customers": { "value": 41, "change": 17, "previous": 35 }
},
"charts": {
"revenue_over_time": [
{ "label": "09/30", "orders": 7, "revenue": 24500 },
{ "label": "10/01", "orders": 5, "revenue": 18000 }
],
"orders_by_hour": [
{ "hour": "00:00", "orders": 0, "impressions": 35 },
{ "hour": "01:00", "orders": 1, "impressions": 22 }
],
"orders_by_status": {
"pending": 5,
"confirmed": 4,
"processing": 2,
"shipped": 9,
"delivered": 20,
"cancelled": 6,
"returned": 2
},
"top_products": [
{
"id": 12,
"name": "Classic watch",
"image": "https://cdn.dzbuild.app/uploads/products/123/123_1700000000_example.webp",
"qty_sold": 14,
"revenue": 49000,
"views": 380
}
],
"visitors_over_time": [
{ "label": "09/30", "page_views": 690, "unique_visitors": 215, "orders": 7 },
{ "label": "10/01", "page_views": 702, "unique_visitors": 230, "orders": 5 }
],
"devices": {
"desktop": { "count": 510, "percent": 11 },
"mobile": { "count": 4180, "percent": 87 },
"tablet": { "count": 120, "percent": 2 }
},
"traffic_sources": [
{ "source": "facebook", "count": 2900, "percent": 60 },
{ "source": "direct", "count": 1210, "percent": 25 },
{ "source": "tiktok", "count": 700, "percent": 15 }
],
"top_wilayas": [
{ "wilaya": "الجزائر", "orders": 9, "revenue": 41000 },
{ "wilaya": "وهران", "orders": 6, "revenue": 27500 }
]
}
}
}
The period
Field | Meaning |
| Start and end of the period, |
| Start and end of the comparison period. |
| The |
| Bucket size of |
KPIs
Each KPI has three numbers: value for the period, previous for the comparison period, and change, the percent change rounded to a whole number. When previous is 0 or below, change is 100 if value is above 0, and 0 otherwise. Amounts are rounded to whole numbers.
KPI | What it counts |
| Orders created in the period, whatever their status. |
| Orders delivered in the period, counted on the day they were delivered. |
| Orders created in the period that are now cancelled. |
| Owner only. Subtotal minus discount of the orders delivered in the period. Shipping and payment fees are not included. |
| Owner only. |
| Owner only. Average order total of the orders created in the period, cancelled and returned orders left out. |
| Distinct visitors in the period, store pages and landing pages together. |
| Page views in the period, store pages and landing pages together. |
|
|
| Customer records created in the period. |
These KPIs come from different sets of orders, so they do not add up: total_revenue ÷ total_orders is not avg_order_value.
Charts
Chart | Content |
| One entry per bucket: |
| Always 24 entries, |
| Orders created in the period by current status: |
| Up to 10 products by quantity sold in the orders created in the period, cancelled and returned orders left out. Each has |
| One entry per bucket: |
| Page views by device: |
| Up to 6 sources by page views, busiest first, each with |
| Up to 10 wilayas by number of orders created in the period, all statuses: |
Labels follow group_by: 00:00 to 23:00 for hour (24 entries; a two-day custom period adds both days into the same hours), MM/DD for day, and the English month and year for month, such as Sep 2026. Days after today and months after the current one are left out.
The platform records source as direct, facebook, instagram, tiktok, google, youtube, twitter, snapchat, telegram or other. A visit whose link carries utm_source is classed by that tag (fb counts as facebook, ig as instagram, x as twitter, any tag not in the list as other); a visit without it is classed by the site it came from.
Errors
HTTP | Code | Cause |
400 |
|
|
401 |
| Bad or missing key. |
402 |
| The store's monthly request quota is used up. See Rate limits. |
403 |
| "Missing scope: analytics:read", or a personal key whose store is not on an active Enterprise plan ("API access requires an active Enterprise plan"). |
429 |
| The store's per-minute cap, shared by all of its keys, or the per-install cap of an installed app's token. Wait for |
Known limits
Month ends. When today's day number does not exist in the previous month, as on 31 October,
range=last_monthreturns the current month andrange=this_monthis compared with the current month itself.last_monthis also compared with itself when the day does not exist two months back, as on 30 April. On those days, ask for the dates you need withrange=custom.