# Catalogue d'événements

Chaque payload webhook est enveloppée :

```
{

  "event":       "<event name>",

  "store_id":    13,

  "occurred_at": "2026-04-30T21:18:21+00:00",

  "data":        { /* propre à l'événement, documenté ci-dessous */ },

  "delivery_id": "9f2c41ab77e05d18"

}
```

Cette page documente le champ `data` de chaque événement.

## Événements de commande[​](#événements-de-commande "Lien direct vers Événements de commande")

Les événements de commande API v1 ignorent le dashboard et le suivi transporteur

Un événement de statut de commande se déclenche quand le statut est modifié via l'API, avec `PATCH /v1/orders/{id}` ou `POST /v1/orders/{id}/cancel`, et quand quelqu'un appuie sur le bouton de confirmation ou d'annulation d'une notification Telegram de nouvelle commande. Ces deux boutons déclenchent `order.confirmed` et `order.cancelled` aussi pour les commandes de la boutique et des landing pages, qui n'ont jamais envoyé `order.created`. Confirmer ou expédier depuis le dashboard DZBuild, l'envoi groupé en livraison, `POST /v1/orders/{id}/send-to-delivery` et les mises à jour automatiques du suivi transporteur ne déclenchent **rien** ici.

Il y a par ailleurs 7 statuts de commande mais seulement **5** événements de statut : les transitions vers `pending` et vers `processing` n'émettent absolument rien. Une commande peut donc passer `pending → processing → shipped` et vous ne verrez qu'un seul `order.shipped`.

S'il vous faut des événements couvrant toutes les sources de commandes et tous les changements de statut, utilisez plutôt l'addon Webhooks marchand sur `/dashboard/webhooks` — voir la comparaison dans la [Vue d'ensemble des Webhooks](https://dzbuild.com/fr/fr/api-docs/webhooks/overview.md).

### `order.created`[​](#ordercreated "Lien direct vers ordercreated")

Déclenché **uniquement** pour les commandes créées via `POST /v1/orders`. Les commandes passées sur la boutique, sur une landing page ou créées manuellement au dashboard ne déclenchent pas cet événement — si vous y branchez votre logistique, vous manquerez l'écrasante majorité des commandes du marchand.

```
{

  "data": {

    "order_id":       6894,

    "order_number":   "ORD-13-20260317-1A2B3C4D",

    "customer_phone": "0555000000",

    "total":          1000

  }

}
```

Ces quatre clés constituent toute la payload. Appelez `GET /v1/orders/{id}` s'il vous faut autre chose.

### `order.confirmed`[​](#orderconfirmed "Lien direct vers orderconfirmed")

Déclenché à la transition vers `confirmed`. Avec le réglage par défaut de **Déduction du stock** (à la confirmation), le stock est décrémenté à ce moment. Sur une boutique réglée sur **Dès la réception de la commande**, une commande passée après ce choix a vu son stock déduit à sa création, et la confirmer ne déduit rien de plus.

```
{

  "data": {

    "order_id":   6894,

    "old_status": "pending",

    "new_status": "confirmed"

  }

}
```

### `order.shipped`[​](#ordershipped "Lien direct vers ordershipped")

```
{ "data": { "order_id": 6894, "old_status": "processing", "new_status": "shipped" } }
```

`old_status` peut être un état dont on ne vous a jamais parlé — dans cet exemple, le passage à `processing` n'a déclenché aucun événement propre.

### `order.delivered`[​](#orderdelivered "Lien direct vers orderdelivered")

```
{ "data": { "order_id": 6894, "old_status": "shipped", "new_status": "delivered" } }
```

### `order.cancelled`[​](#ordercancelled "Lien direct vers ordercancelled")

Déclenché quand une commande passe à `cancelled` depuis `pending`, `confirmed` ou `processing` — ce sont les seuls états depuis lesquels l'annulation est autorisée. `POST /v1/orders/{id}/cancel` sur une commande `shipped` ou `delivered` renvoie `400 bad_request` et ne déclenche aucun événement. Si la commande était déjà dans un état à stock engagé, le stock est restitué avant que cet événement parte.

```
{ "data": { "order_id": 6894, "old_status": "confirmed", "new_status": "cancelled" } }
```

### `order.returned`[​](#orderreturned "Lien direct vers orderreturned")

```
{ "data": { "order_id": 6894, "old_status": "delivered", "new_status": "returned" } }
```

## Événements de paiement[​](#événements-de-paiement "Lien direct vers Événements de paiement")

### `payment.received`[​](#paymentreceived "Lien direct vers paymentreceived")

**Réservé — non émis actuellement.** Le nom est accepté dans le tableau `events` à l'enregistrement et apparaît dans `allowed_events`, mais rien ne le déclenche. Les changements de statut de paiement n'arriveront pas sur votre endpoint ; lisez `GET /v1/orders/{id}` si vous en avez besoin.

## Suivi des signups / événements[​](#suivi-des-signups--événements "Lien direct vers Suivi des signups / événements")

### `signup.counted`[​](#signupcounted "Lien direct vers signupcounted")

Déclenché quand un appel `/v1/signups` arrive et a réellement été compté (pas un doublon).

```
{

  "data": {

    "key_id":  "dzpub_live_0123456789abc",

    "source":  "landing-page-1",

    "country": "DZ"

  }

}
```

Pour des raisons de confidentialité, nous ne renvoyons PAS `email`, `phone` ni `external_user_id` dans le webhook — vos propres systèmes ont déjà ces valeurs. Le webhook est le signal « ce signup a été compté, répercutez-le dans votre CRM ».

### `event.recorded`[​](#eventrecorded "Lien direct vers eventrecorded")

**Réservé — non émis actuellement.** `POST /v1/events` enregistre l'événement et incrémente la consommation, mais ne déclenche aucun webhook.

## Événements produit[​](#événements-produit "Lien direct vers Événements produit")

### `product.stock_low`[​](#productstock_low "Lien direct vers productstock_low")

**Réservé — non émis actuellement.** Il n'existe aucun push de stock bas aujourd'hui.

Le champ sous-jacent est bien réel, en revanche : `GET /v1/products/{id}` renvoie `low_stock_alert` à côté de `stock_quantity` sous `inventory`, vous pouvez donc surveiller la condition vous-même par polling.

## Interne / test[​](#interne--test "Lien direct vers Interne / test")

### `webhook.test`[​](#webhooktest "Lien direct vers webhooktest")

Déclenché par `POST /v1/webhooks/{id}/test`. Vous permet de vérifier que votre endpoint est joignable sans attendre un vrai événement.

```
{ "data": { "ts": 1717112657 } }
```

Il ne peut pas faire l'objet d'un abonnement — inclure `webhook.test` dans le tableau `events` à l'enregistrement renvoie `400 bad_request` `"unknown event: webhook.test. Allowed: …"`. Un test est livré au webhook sur lequel vous l'appelez, indépendamment de sa liste d'abonnements.

## En-têtes (chaque événement)[​](#en-têtes-chaque-événement "Lien direct vers En-têtes (chaque événement)")

```
Content-Type:    application/json

User-Agent:      dzbuild-webhook/1

X-DZ-Timestamp:  <unix seconds>

X-DZ-Signature:  t=<unix seconds>,v1=<hex hmac-sha256>

X-DZ-Delivery-Id: <numeric delivery id>
```

`X-DZ-Delivery-Id` est un id numérique de livraison (par ex. `4127`). Il est stable à chaque retry de cette livraison, et il n'est **pas** la même valeur que le `delivery_id` de 16 caractères hex présent dans le body JSON. La signature ne couvre pas cet en-tête : dédupliquez sur le `delivery_id` du body.

## Versioning[​](#versioning "Lien direct vers Versioning")

Nous ajoutons librement de nouveaux events en v1 (additif). Quand nous changeons la **forme du `data` d'un event existant**, c'est un changement qui exige une v2 et un nouveau préfixe de chemin. Votre code peut donc compter sur :

* `event` est stable.
* De nouveaux champs de premier niveau peuvent apparaître dans `data`.
* Les types et significations existants ne changeront pas sans v2.
* L'ordre des clés de `data` n'est **pas** garanti.
