Recevoir des webhooks signés
GuideDéveloppeursDepuis la version 1.5.0
Sur cette page
La passerelle livre les évènements de votre tenant à votre URL, signés au format Standard Webhooks. Vérifiez la signature avant tout traitement.
Côté produit : Plan asynchrone et courtiers ; côté exploitation : Publier et consommer sur un courtier.
Ce que vous recevez
| Élément | Valeur |
|---|---|
| Méthode et corps | POST, un CloudEvent JSON (Content-Type: application/cloudevents+json) |
webhook-id |
L'identifiant de l'évènement (id du CloudEvent), stable entre deux tentatives |
webhook-timestamp |
Secondes Unix de la tentative |
webhook-signature |
v1,<base64> ; deux valeurs séparées par une espace pendant une rotation du secret |
| Secret | whsec_<base64>, remis par l'exploitant |
La signature est HMAC-SHA256(secret décodé, "<webhook-id>.<webhook-timestamp>.<corps brut>") en base64.
Vérifier
import base64, hashlib, hmac, time
def verify(secret: str, headers, body: bytes, tolerance=300) -> bool:
key = base64.b64decode(secret.removeprefix("whsec_"))
msg_id, ts = headers["webhook-id"], headers["webhook-timestamp"]
if abs(time.time() - int(ts)) > tolerance:
return False
mac = base64.b64encode(hmac.new(key, f"{msg_id}.{ts}.".encode() + body, hashlib.sha256).digest()).decode()
return any(hmac.compare_digest(mac, s.split(",", 1)[1]) for s in headers["webhook-signature"].split())func verify(secret string, h http.Header, body []byte) bool {
key, _ := base64.StdEncoding.DecodeString(strings.TrimPrefix(secret, "whsec_"))
m := hmac.New(sha256.New, key)
fmt.Fprintf(m, "%s.%s.", h.Get("webhook-id"), h.Get("webhook-timestamp"))
m.Write(body)
want := base64.StdEncoding.EncodeToString(m.Sum(nil))
for _, s := range strings.Fields(h.Get("webhook-signature")) {
if v, ok := strings.CutPrefix(s, "v1,"); ok && hmac.Equal([]byte(v), []byte(want)) {
return true
}
}
return false // vérifiez aussi l'écart de webhook-timestamp
}Les bibliothèques officielles Standard Webhooks (standardwebhooks en Python, JavaScript, Go...)
font la même vérification. Lisez le corps brut, avant tout décodage JSON.
Répondre
| Votre réponse | Ce que fait la passerelle |
|---|---|
2xx |
Livré |
408, 429, 5xx, délai, connexion refusée |
Nouvelle tentative, en respectant votre Retry-After (plafonné) |
Autre 4xx |
Pas de nouvelle tentative |
| Tentatives épuisées | L'évènement part en file de rebut de l'exploitant |
Répondez vite et traitez ensuite ; dédupliquez sur webhook-id : la livraison est au moins une fois.