flexway
FRENParler à un expert

Recevoir des webhooks signés

GuideDéveloppeursDepuis la version 1.5.0

Markdown

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.

Étapes suivantes