Les webhooks sont des notifications push temps réel de DZBuild vers votre serveur quand quelque chose se passe sur votre boutique. Utilisez-les au lieu du polling — moins de charge, latence plus basse, et les livraisons webhook ne comptent pas dans votre quota mensuel de requêtes.
ℹ️ Info — Il existe deux systèmes de webhooks DZBuild distincts
Choisissez le bon avant de construire.
Addon Webhooks marchand | Webhooks API v1 (cette section) | |
Configuration |
|
|
Qui peut l'utiliser | Plan Unlimited et au-delà | Les boutiques avec un plan Enterprise actif, via une clé API du marchand (les jetons d'application installée sont refusés) |
Endpoints par boutique | 1 en Unlimited, 3 en Enterprise | Aucune limite n'est appliquée |
Signature |
| Même format : |
Commandes couvertes |
| Les commandes créées ou mises à jour via l'API, plus les confirmations et annulations faites avec les boutons des notifications Telegram de nouvelle commande, commandes de la boutique et des landing pages comprises |
Livré depuis | Les plages IP Cloudflare | Les adresses de sortie propres à DZBuild — demandez la liste actuelle au support |
Extras | Interface de journal des livraisons, régénération du secret, validation HTTPS de la cible, désactivation automatique après 10 échecs consécutifs | Validation HTTPS de la cible |
Si tout ce dont vous avez besoin, ce sont des notifications de commande fiables, l'addon est le meilleur produit. Utilisez les webhooks API v1 quand votre intégration parle déjà à l'API REST.
Pourquoi des webhooks
Comparez :
Polling — votre code appelle GET /v1/orders?since=... chaque minute. 1440 appels/jour, 1440 round-trips, votre quota brûle uniformément, et la latence « commande créée → votre code le sait » est de 60 s.
Webhooks — vous enregistrez https://yourapp/webhooks une fois. Chaque commande créée via POST /v1/orders met une livraison en file, et la file se vide en continu : la latence est donc généralement inférieure à une minute. Zéro polling, zéro gâchis de quota.
⚠️ Attention — Les webhooks API v1 ignorent les commandes passées sur la boutique et les changements faits au dashboard
order.created se déclenche 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 rien ici. Les changements de statut faits au dashboard ne déclenchent rien non plus ; seuls les changements faits via l'API et les boutons de confirmation et d'annulation des notifications Telegram de nouvelle commande en déclenchent. Voir le Catalogue d'événements.
Le polling n'est meilleur que quand : - Votre endpoint n'est pas joignable depuis Internet (pollez depuis votre réseau interne). - Vous n'avez pas de serveur (pollez depuis une lambda planifiée / cron).
Comment fonctionne la livraison
Une écriture API v1 a lieu
│
▼
Une livraison est mise en file pour chaque webhook abonné à cet événement
│
▼
La file se vide en continu — généralement en moins d'une minute
│
▼
Body signé ─────► POST votre URL (5 s connexion, 10 s au total)
│
├─ 2xx : marque livré, fini
├─ 5xx, 408, 429, timeout, échec DNS ou TLS : re-tenté avec backoff
├─ tout autre 4xx, ou un 3xx : file morte immédiatement, pas de retry
└─ 5 tentatives échouées : file morte, plus de retry
Comportement des retries
Les réponses 5xx, 408 et 429 et les échecs réseau (timeout, DNS, TLS) sont réessayés 1 min, 5 min, 30 min puis 2 h après l'échec. Après le 5e échec, la livraison passe en file morte et n'est plus envoyée.
Tout autre 4xx, et tout 3xx, n'est tenté qu'une fois : la livraison passe aussitôt en file morte et n'est jamais réessayée. Les redirections ne sont pas suivies : un
301/302compte comme un échec.
Il n'y a pas de désactivation automatique. Le failure_count du webhook s'incrémente une fois par tentative échouée et retombe à 0 au premier succès ; status reste active.
Conséquences pratiques :
Répondez 2xx vite. Si vous ne pouvez pas traiter une payload, répondez quand même 2xx et jetez-la ; un 5xx vous coûte quatre livraisons de plus du même body sur environ 2 h 30.
Ne comptez pas sur les retries pour un endpoint lent. Cinq échecs en 2 h 30 environ et la livraison est abandonnée. Persistez le body dans votre propre file et acquittez immédiatement.
Réconciliez par polling. Comme une livraison est abandonnée après cinq échecs, lancez un balayage périodique
GET /v1/orders?since=...comme filet de sécurité.sincefiltre sur la date de création de la commande : le balayage retrouve les commandes dont vous avez manqué leorder.created; pour un changement de statut manqué, relisez les commandes que vous suivez encore et comparez leurstatus.
Ce qui compte comme un « succès »
HTTP 200, 201, 202, 204 (n'importe quel 2xx) — succès.
HTTP 4xx autre que
408et429(400, 401, 403, 404, 422, etc.) : pas de retry, la livraison passe directement en file morte. Corrigez votre endpoint et re-testez viaPOST /v1/webhooks/{id}/test.HTTP 3xx : pas de retry, file morte immédiate. Nous ne suivons pas les redirections ; pointez le webhook sur l'URL finale.
Timeout, échec DNS, échec TLS : re-tentés comme un 5xx. Les certificats TLS sont vérifiés strictement : un certificat auto-signé échoue à chaque tentative.
HTTP 5xx,
408et429: re-tentés selon le calendrier ci-dessus, 5 tentatives au total.
Modèle de sécurité
Ce qu'on envoie
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>
Signature
X-DZ-Signature est calculée avec le secret que POST /v1/webhooks vous a renvoyé à l'enregistrement du webhook :
X-DZ-Signature: t=<unix seconds>,v1=<hex hmac-sha256>expected = hex( hmac_sha256( WEBHOOK_SECRET, t + "." + raw_body ) )if (!constant_time_equal(expected, v1)) reject 401 if (abs(now - t) > 300) reject 401 # fenêtre rejeu ±5 min
Pour vérifier une livraison :
Découpez l'en-tête sur
,et lisez les valeurstetv1.Calculez le HMAC-SHA256 de
t + "." + raw_bodyavec le secret du webhook,raw_bodyétant exactement les octets reçus, puis encodez-le en hex.Comparez le résultat à
v1à temps constant.Rejetez la livraison si
ts'écarte de plus de 300 secondes de votre horloge.
Chaque tentative est signée au moment de l'envoi : un retry porte donc un nouveau t et un nouveau v1 sur le même body. Le code en quatre langages est sur Vérifier les signatures.
⚠️ Attention — Webhooks enregistrés avant la signature par webhook
Un webhook créé avant que DZBuild ne signe avec le secret propre à chaque webhook garde l'ancienne signature : une valeur hex nue sans partie t=, calculée avec une clé que DZBuild ne communique pas. Vous ne pouvez pas la vérifier. Supprimez ce webhook et enregistrez-le de nouveau : le nouvel enregistrement renvoie un secret qui signe chaque livraison.
Ce que vous devez faire
Vérifiez la signature avant d'agir. Rejetez toute livraison dont le
v1ne correspond pas, avant de parser le JSON ou de toucher à une commande.Servez du HTTPS.
POST /v1/webhooksrefuse touteurlqui ne commence pas parhttps://, et les certificats sont vérifiés strictement.Vérifiez que le timestamp est dans 5 min de l'horloge serveur — protection anti-rejeu à moindre coût.
Utilisez les bytes raw du body pour le HMAC. Ne re-sérialisez pas le JSON.
Soyez idempotent. La même livraison peut arriver plusieurs fois : après un 5xx, un
408, un429ou un timeout, elle est renvoyée avec le même body. Dédupliquez uniquement sur ledelivery_iddu body signé.
Ce qu'on ne fait pas
Pas d'auth sortant en mTLS. Si votre endpoint le requiert, mettez un reverse proxy qui strip/ajoute mTLS devant.
On n'envoie pas les livraisons API v1 depuis les plages IP Cloudflare : n'autoriser que celles-ci bloque donc toutes les livraisons. S'il vous faut une allow-list IP, demandez au support les adresses de sortie actuelles — elles peuvent changer. (L'addon Webhooks marchand, lui, part bien des plages Cloudflare.)
Enveloppe de payload
Chaque body webhook a la même forme externe :
{
"event": "order.confirmed",
"store_id": 13,
"occurred_at": "2026-04-30T21:18:21+00:00",
"data": { "order_id": 6894, "old_status": "pending", "new_status": "confirmed" },
"delivery_id": "9f2c41ab77e05d18"
}
Champ | Notes |
| Type d'événement (liste complète dans Catalogue d'événements). |
| Votre store id — utile si vous avez plusieurs webhooks sur le même handler. |
| Quand l'événement a eu lieu chez nous, ISO 8601 + TZ. |
| Payload propre à l'événement. Voir Catalogue pour la forme. |
| Chaîne de 16 caractères hex, unique par livraison (un webhook × un événement). Elle est identique octet pour octet à chaque retry — c'est ce qui la rend utilisable pour la déduplication. |
L'en-tête X-DZ-Delivery-Id est une valeur différente : un id numérique de livraison, par exemple 4127. Il est stable d'un retry à l'autre, mais la signature ne le couvre pas : quiconque atteint votre URL peut y mettre n'importe quelle valeur. Dédupliquez uniquement sur le delivery_id du body signé.
Quota
Les livraisons webhook ne sont aujourd'hui ni comptabilisées ni plafonnées. Une valeur webhooks_per_month est remontée par GET /v1/usage et GET /v1/quotas, mais rien ne l'incrémente et rien ne l'applique. Les tentatives de livraison ne consomment pas non plus votre quota API requests_per_month.
Ce n'est pas un permis d'être lent : un endpoint qui répond 5xx reçoit le même body jusqu'à quatre fois de plus sur environ 2 h 30 (voir Comportement des retries).
La suite
Enregistrement —
POST /v1/webhooksavec body, réponse, exemples.Catalogue d'événements — chaque event avec sample data.
Vérifier les signatures — code en 4 langages.