Webhooks
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 (important) les livraisons webhook ne comptent pas dans votre quota mensuel de requêtes.
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. On POST dessus à chaque création de commande. Latence ~2-5 s. Zéro polling. Zéro gâchis de quota.
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
Commande/événement à l'origine
│
▼
INSERT row dans api_v1_webhook_deliveries
│
▼
Cron drain chaque minute (next_retry_at <= NOW())
│
▼
Signe HMAC du body ─────► POST votre URL avec timeout 10 s
│ │
│ ├─ 2xx → marque livré, fini
│ ├─ 5xx → retry : 1m, 5m, 30m, 2h, 12h
│ ├─ 4xx → ack comme poison ; PAS de retry
│ └─ pas de réponse (timeout / DNS) → retry
│
└─ 5 échecs → DLQ
Calendrier de retry
Après chaque tentative échouée, next_retry_at est mis à now() + delay[attempt] :
| Tentative | Délai |
|---|---|
| 1 | 1 minute |
| 2 | 5 minutes |
| 3 | 30 minutes |
| 4 | 2 heures |
| 5 | 12 heures |
| 6e | DLQ — intervention manuelle |
Fenêtre totale de retry ~14,5 h. Au-delà, la livraison part en DLQ et failure_count du webhook s'incrémente. Cinq DLQ consécutifs auto-désactivent le webhook (status → dead) ; contactez le support pour reset.
Ce qui compte comme un « succès »
- HTTP 200, 201, 202, 204 (n'importe quel 2xx) — succès.
- HTTP 4xx (400, 401, 403, 404, 422 …) — pas de retry. On traite 4xx comme « votre endpoint rejette définitivement cette payload » ; les retries n'aideront pas. Fixez votre endpoint et re-testez via
POST /v1/webhooks/{id}/test. - HTTP 5xx, timeout, échec DNS, échec TLS — retry.
Si vous voulez qu'on retry sur un 4xx précis (rare), répondez 503 Service Unavailable au lieu d'un 4xx.
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: <hex hmac-sha256>
X-DZ-Delivery-Id: <id>
Signature
X-DZ-Signature = hex( hmac_sha256( WEBHOOK_SECRET, X-DZ-Timestamp + "." + sha256(body) ) )
Le WEBHOOK_SECRET est ce que vous avez récupéré en enregistrant le webhook (POST /v1/webhooks). On ne le réexpose jamais — stockez-le.
Ce que vous devez faire
- Vérifier la signature sur chaque requête (voir Vérifier les signatures).
- Vérifier que le timestamp est dans 5 min de l'horloge serveur — rejette les rejeux.
- Utiliser les bytes raw du body pour le hash — ne re-sérialisez pas le JSON.
- Soyez idempotent —
X-DZ-Delivery-Idest unique par tentative, mais le même événement logique PEUT être livré plusieurs fois (réseau, retries-après-succès). Dédupliquez côté vous viadelivery_idou les ids de l'event.
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.
- Pas de IP-lockout. On envoie depuis CF Workers — l'IP source est dans les ranges Cloudflare. Pour whitelist, utilisez la liste IP 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": "abc123def456"
}
| Champ | Notes |
|---|---|
event | Type d'événement (liste complète dans Catalogue d'événements). |
store_id | Votre store id — utile si vous avez plusieurs webhooks sur le même handler. |
occurred_at | Quand l'événement a eu lieu chez nous, ISO 8601 + TZ. |
data | Payload propre à l'événement. Voir Catalogue pour la forme. |
delivery_id | Unique par tentative. Utilisez-le pour l'idempotence. |
Quota
Chaque tentative de livraison — succès, 4xx, retry — compte 1 dans webhooks_per_month. Un seul event qui retry 5 fois coûte 5. Donc :
- Gardez votre endpoint fiable (2xx rapide) → 1 tentative par event.
- Les échecs coûtent plus cher → fixez les bugs vite pour ne pas brûler le quota.
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.