# Analytics

`GET /v1/analytics` renvoie les chiffres que montre la page d'accueil du tableau de bord pour une période : dix KPIs, chacun avec sa valeur sur une période de comparaison et la variation, et huit séries de graphiques. Utilisez-le pour les rapports de vos clients ou un export vers un outil BI, au lieu de recalculer les chiffres depuis `GET /v1/orders`. L'API et le tableau de bord partagent les mêmes définitions et le même cache : pour une même période, ils affichent les mêmes chiffres. Le sens de chaque chiffre pour le marchand est expliqué sur la page [Analytics](https://dzbuild.com/fr/fr/docs/marketing/analytics.md) de la documentation marchand.

L'API compte toujours tout le trafic : pages de la boutique et pages de destination ensemble. Le filtre de trafic du tableau de bord (pages de destination seulement, ou boutique seulement) n'a pas d'équivalent ici.

## Avant de commencer[​](#avant-de-commencer "Lien direct vers Avant de commencer")

* La clé a besoin de `analytics:read`. Les clés créées depuis le tableau de bord (**Paramètres → API**, `/dashboard/api`) l'ont depuis la v1.7. **Les portées sont figées à la création de la clé** : une clé plus ancienne répond `403 forbidden` avec « Missing scope: analytics
  <!-- -->
  :read
  <!-- -->
  ». Créez alors une nouvelle clé depuis le tableau de bord. Une clé créée par `POST /v1/keys` n'obtient que les portées que détient la clé qui l'a créée.
* Les clés personnelles demandent une boutique avec un plan Enterprise actif. Le jeton d'une app installée n'est pas lié à Enterprise, mais il lui faut `analytics:read` parmi les portées que le marchand a acceptées. Voir [Introduction](https://dzbuild.com/fr/fr/api-docs/intro.md).
* Le revenu, le profit et le panier moyen, ainsi que les valeurs `revenue` dans les graphiques, ne sont envoyés que si la clé appartient au compte du propriétaire de la boutique. Sinon ces champs sont absents de la réponse : ils ne valent ni `0` ni `null`.

| Portée           | Description                                                                                                                                                   |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `analytics:read` | Lire les statistiques et les KPIs de la boutique. Incluse dans les clés marchand créées à partir de la v1.7 ; une clé plus ancienne demande une nouvelle clé. |

## `GET /v1/analytics`[​](#get-v1analytics "Lien direct vers get-v1analytics")

Le rapport d'une période.

**Auth :** clé plateforme avec `analytics:read`.

### Paramètres de requête[​](#paramètres-de-requête "Lien direct vers Paramètres de requête")

| Param   | Type         | Défaut       | Notes                                                                                                                                 |
| ------- | ------------ | ------------ | ------------------------------------------------------------------------------------------------------------------------------------- |
| `range` | string       | `this_month` | `today`, `yesterday`, `7d`, `30d`, `this_month`, `last_month`, `this_year` ou `custom`. Toute autre valeur renvoie `400 bad_request`. |
| `from`  | `YYYY-MM-DD` | aucun        | Premier jour. Obligatoire avec `range=custom`, ignoré sinon.                                                                          |
| `to`    | `YYYY-MM-DD` | aucun        | Dernier jour. Obligatoire avec `range=custom`, ignoré sinon. Jamais avant `from`, au plus 365 jours après.                            |

### Périodes[​](#périodes "Lien direct vers Périodes")

| `range`      | Période                                           | Comparée à                                 | `group_by`               |
| ------------ | ------------------------------------------------- | ------------------------------------------ | ------------------------ |
| `today`      | Aujourd'hui                                       | Hier                                       | `hour`                   |
| `yesterday`  | Hier                                              | La veille                                  | `hour`                   |
| `7d`         | Aujourd'hui et les 6 jours d'avant                | Les 7 jours qui précèdent                  | `day`                    |
| `30d`        | Aujourd'hui et les 29 jours d'avant               | Les 30 jours qui précèdent                 | `day`                    |
| `this_month` | Du 1er au dernier jour du mois en cours           | Tout le mois précédent                     | `day`                    |
| `last_month` | Tout le mois précédent                            | Le mois d'avant                            | `day`                    |
| `this_year`  | Du 1er janvier au 31 décembre de l'année en cours | Toute l'année précédente                   | `month`                  |
| `custom`     | De `from` à `to`, les deux jours compris          | Le même nombre de jours juste avant `from` | `hour`, `day` ou `month` |

Pour `custom`, `group_by` vaut `hour` quand `to` est `from` ou le lendemain, `day` quand `to` tombe au plus 90 jours après `from`, et `month` au-delà. `this_month` et `this_year` vont jusqu'à la fin du mois ou de l'année : ils comparent donc les jours écoulés à un mois ou une année précédente entière.

Le rapport est mis en cache 120 secondes par boutique et par période, et le tableau de bord lit le même cache. Un appel peut renvoyer des chiffres vieux de deux minutes au plus, et les appels faits dans cet intervalle obtiennent les mêmes chiffres.

### Requête[​](#requête "Lien direct vers Requête")

```
curl 'https://api.dzbuild.app/v1/analytics?range=7d' \

  -H "Authorization: Bearer $DZ_KEY"
```

Une période personnalisée :

```
curl 'https://api.dzbuild.app/v1/analytics?range=custom&from=2026-09-01&to=2026-09-30' \

  -H "Authorization: Bearer $DZ_KEY"
```

### Réponse 200[​](#réponse-200 "Lien direct vers Réponse 200")

La réponse pour `range=7d` le 6 octobre 2026, à une clé créée par le propriétaire de la boutique. Les séries temporelles et les listes sont coupées après leurs premiers éléments.

```
{

  "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 }

      ]

    }

  }

}
```

### La période[​](#la-période "Lien direct vers La période")

| Champ                  | Signification                                                                                     |
| ---------------------- | ------------------------------------------------------------------------------------------------- |
| `from`, `to`           | Début et fin de la période, `YYYY-MM-DD HH:MM:SS`, heure d'Alger.                                 |
| `prev_from`, `prev_to` | Début et fin de la période de comparaison.                                                        |
| `label`                | Le `range` demandé.                                                                               |
| `group_by`             | Taille des intervalles de `revenue_over_time` et `visitors_over_time` : `hour`, `day` ou `month`. |

### KPIs[​](#kpis "Lien direct vers KPIs")

Chaque KPI porte trois nombres : `value` pour la période, `previous` pour la période de comparaison, et `change`, la variation en pourcentage arrondie à l'entier. Quand `previous` vaut `0` ou moins, `change` vaut `100` si `value` est supérieur à `0`, et `0` sinon. Les montants sont arrondis à l'entier.

| KPI                | Ce qu'il compte                                                                                                                                                   |
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `total_orders`     | Commandes créées dans la période, quel que soit leur statut.                                                                                                      |
| `delivered_orders` | Commandes livrées dans la période, comptées le jour de leur livraison.                                                                                            |
| `cancelled_orders` | Commandes créées dans la période et désormais annulées.                                                                                                           |
| `total_revenue`    | Propriétaire uniquement. Sous-total moins remise des commandes livrées dans la période. Livraison et frais de paiement non compris.                               |
| `total_profit`     | Propriétaire uniquement. `total_revenue` moins quantité × prix de revient des articles de ces commandes. Un produit sans prix de revient compte pour un coût nul. |
| `avg_order_value`  | Propriétaire uniquement. Total moyen des commandes créées dans la période, commandes annulées et retournées exclues.                                              |
| `total_visitors`   | Visiteurs distincts dans la période, pages de la boutique et pages de destination ensemble.                                                                       |
| `page_views`       | Pages vues dans la période, pages de la boutique et pages de destination ensemble.                                                                                |
| `conversion_rate`  | `total_orders` ÷ `total_visitors` × 100, avec une décimale. `0` quand il n'y a eu aucun visiteur.                                                                 |
| `new_customers`    | Fiches clients créées dans la période.                                                                                                                            |

Ces KPIs viennent d'ensembles de commandes différents, ils ne se recoupent donc pas : `total_revenue` ÷ `total_orders` ne donne pas `avg_order_value`.

### Graphiques[​](#graphiques "Lien direct vers Graphiques")

| Graphique            | Contenu                                                                                                                                                                                                                                                                                                                                                               |
| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `revenue_over_time`  | Un élément par intervalle : `label`, les `orders` créées dans l'intervalle et, pour le propriétaire uniquement, `revenue`, la somme des totaux de celles qui sont désormais livrées. Ce n'est pas `total_revenue`, qui compte au jour de livraison et laisse de côté les frais de livraison.                                                                          |
| `orders_by_hour`     | Toujours 24 éléments, de `00:00` à `23:00` : les commandes créées et les pages vues (`impressions`) à cette heure de la journée, sur toute la période.                                                                                                                                                                                                                |
| `orders_by_status`   | Commandes créées dans la période par statut actuel : `pending`, `confirmed`, `processing`, `shipped`, `delivered`, `cancelled` et `returned`.                                                                                                                                                                                                                         |
| `top_products`       | Jusqu'à 10 produits par quantité vendue dans les commandes créées dans la période, commandes annulées et retournées exclues. Chacun a `id`, `name`, `image` (URL de l'image principale ou `null`), `qty_sold`, `views` (visiteurs distincts sur le produit dans la période) et, pour le propriétaire uniquement, `revenue` (quantité × prix inscrit sur la commande). |
| `visitors_over_time` | Un élément par intervalle : `label`, `page_views`, `unique_visitors` et `orders`. Un visiteur qui revient un autre jour compte dans les deux intervalles, donc la somme des `unique_visitors` peut dépasser `total_visitors`.                                                                                                                                         |
| `devices`            | Pages vues par appareil : clés `desktop`, `mobile` et `tablet`, chacune avec `count` et `percent`. Un appareil sans vue n'a pas de clé, et le champ est un tableau vide `[]` quand la période n'a eu aucune visite.                                                                                                                                                   |
| `traffic_sources`    | Jusqu'à 6 sources par pages vues, la plus forte en premier, chacune avec `source`, `count` et `percent`. `percent` est la part parmi les sources listées.                                                                                                                                                                                                             |
| `top_wilayas`        | Jusqu'à 10 wilayas par nombre de commandes créées dans la période, tous statuts : `wilaya` (le nom en arabe, `غير محدد` pour les commandes sans wilaya), `orders` et, pour le propriétaire uniquement, `revenue`, la somme des totaux de ces commandes quel que soit leur statut.                                                                                     |

Les libellés suivent `group_by` : `00:00` à `23:00` pour `hour` (24 éléments ; une période `custom` de deux jours additionne les deux jours dans les mêmes heures), `MM/DD` pour `day`, et le mois en anglais avec l'année pour `month`, par exemple `Sep 2026`. Les jours après aujourd'hui et les mois après le mois en cours sont omis.

La plateforme enregistre `source` parmi `direct`, `facebook`, `instagram`, `tiktok`, `google`, `youtube`, `twitter`, `snapchat`, `telegram` ou `other`. Une visite dont le lien porte `utm_source` est classée selon ce tag (`fb` compte comme `facebook`, `ig` comme `instagram`, `x` comme `twitter`, tout tag hors de la liste comme `other`) ; une visite sans lui est classée selon le site d'où elle vient.

### Erreurs[​](#erreurs "Lien direct vers Erreurs")

| HTTP | Code             | Cause                                                                                                                                                                                                                                                         |
| ---- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 400  | `bad_request`    | `range` n'est pas l'une des huit valeurs (« Invalid range. Allowed: ... »), ou une période `custom` dont `from` ou `to` manque ou n'est pas au format `YYYY-MM-DD`, ou dont `to` est avant `from` ou plus de 365 jours après (« Invalid date range ... »).    |
| 401  | `unauthorized`   | Clé invalide ou manquante.                                                                                                                                                                                                                                    |
| 402  | `quota_exceeded` | Le quota mensuel de requêtes de la boutique est épuisé. Voir [Limites de taux](https://dzbuild.com/fr/fr/api-docs/rate-limits.md).                                                                                                                            |
| 403  | `forbidden`      | « Missing scope: analytics<!-- -->:read<!-- --> », ou une clé personnelle dont la boutique n'a pas de plan Enterprise actif (« API access requires an active Enterprise plan »).                                                                              |
| 429  | `rate_limited`   | Plafond par minute de la boutique, partagé par toutes ses clés, ou plafond propre à chaque installation pour le jeton d'application installée. Attendez la durée de `Retry-After`. Voir [Limites de taux](https://dzbuild.com/fr/fr/api-docs/rate-limits.md). |

## Limites connues[​](#limites-connues "Lien direct vers Limites connues")

* **Fins de mois.** Quand le numéro du jour n'existe pas dans le mois précédent, comme le 31 octobre, `range=last_month` renvoie le mois en cours et `range=this_month` est comparé au mois en cours lui-même. `last_month` est aussi comparé à lui-même quand le jour n'existe pas deux mois plus tôt, comme le 30 avril. Ces jours-là, demandez les dates voulues avec `range=custom`.
