En production
Webhooks
Livraisons d'événements signées et relancées : points de terminaison, types d'événements, vérification en quatre langages, tests et rejeu.
6 min de lecture
Sur cette page
Points de terminaison
Créez un ou plusieurs points de terminaison avec POST /partner/webhooks/endpoints (name, url, events sous forme de liste séparée par des virgules ou *, et mode). Chacun reçoit son propre secret de signature, affiché une seule fois à la création. Modifiez-les, supprimez-les et listez-les avec les appels /partner/webhooks/endpoint…, ou dans la console.
Types d'événements
| Événement | Envoyé lorsque |
|---|---|
charge.created | Un débit par demande de paiement a été créé. |
charge.completed | Le client a approuvé et l'argent a été transféré. |
charge.declined | Le client a refusé la demande. |
charge.expired | La demande a expiré sans réponse. |
checkout.completed | Une session de paiement hébergé a été payée. |
c2b.confirmation | Un client a payé directement votre caisse ou votre paybill. |
À quoi ressemble une livraison
| En-tête | Valeur |
|---|---|
X-PesaBridge-Event | Le type d'événement, par exemple charge.completed. |
X-PesaBridge-Signature | HMAC-SHA256 en hexadécimal du corps brut de la requête, avec le secret de signature du point de terminaison. |
X-PesaBridge-Timestamp | Heure Unix de la signature de la livraison. |
X-PesaBridge-Signature-V2 | t=<timestamp>,v1=<hex HMAC-SHA256 of "<timestamp>.<raw body>"> : résistant au rejeu. |
X-PesaBridge-Delivery | Identifiant de livraison : journalisez-le et utilisez-le pour ignorer les doublons. |
Vérifier chaque livraison
Calculez le HMAC sur les octets exacts reçus, avant d'analyser le JSON, et comparez en temps constant. Préférez la V2 et rejetez les horodatages de plus de cinq minutes.
import crypto from "node:crypto";
// Express: app.post("/webhook", express.raw({ type: "application/json" }), handler)
function verified(req, secret) {
const [t, v1] = (req.get("X-PesaBridge-Signature-V2") || "").split(",").map((p) => p.split("=")[1]);
if (!t || Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
const want = crypto.createHmac("sha256", secret).update(`${t}.${req.body}`).digest("hex");
return v1?.length === want.length && crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(want));
}import hmac, hashlib, time
def verified(raw_body: bytes, headers, secret: str) -> bool:
parts = dict(p.split("=", 1) for p in headers.get("X-PesaBridge-Signature-V2", "").split(",") if "=" in p)
t, v1 = parts.get("t"), parts.get("v1", "")
if not t or abs(time.time() - int(t)) > 300:
return False
want = hmac.new(secret.encode(), f"{t}.".encode() + raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(v1, want)<?php
$raw = file_get_contents("php://input");
parse_str(str_replace(",", "&", $_SERVER["HTTP_X_PESABRIDGE_SIGNATURE_V2"] ?? ""), $sig);
$ok = isset($sig["t"], $sig["v1"]) && abs(time() - (int)$sig["t"]) <= 300
&& hash_equals(hash_hmac("sha256", $sig["t"] . "." . $raw, getenv("PB_WHSEC")), $sig["v1"]);
http_response_code($ok ? 200 : 401);package webhook
import ("crypto/hmac"; "crypto/sha256"; "encoding/hex")
// Verified checks the V1 signature: hex HMAC-SHA256 of the raw body.
func Verified(raw []byte, sig, secret string) bool {
m := hmac.New(sha256.New, []byte(secret))
m.Write(raw)
return hmac.Equal([]byte(hex.EncodeToString(m.Sum(nil))), []byte(sig))
}Relances et doublons
Répondez par un code 2xx dans les 10 secondes. Toute autre réponse, ou un délai dépassé, entraîne une relance avec un délai exponentiel (1, 2, 4, 8 et 16 minutes, jusqu'à 6 tentatives), après quoi la livraison est marquée failed. À cause des relances, un même événement peut arriver deux fois : rendez votre traitement idempotent sur X-PesaBridge-Delivery ou sur charge_ref.
Nous livrons uniquement vers des adresses HTTPS publiques. Les adresses de réseaux privés et internes sont refusées.
Tester et rejouer
POST /partner/webhooks/testenvoie un événement de test à un point de terminaison.GET /partner/webhooks/deliveriesliste les livraisons récentes avec leur code de statut et leurs tentatives.POST /partner/webhooks/resendrejoue une livraison après la correction de votre traitement.- Le récepteur Echo (
GET /partner/echo/url) capture et vérifie automatiquement les livraisons sans serveur de votre part.
Nos ingénieurs répondent aux questions d'intégration. Envoyez-nous la référence de la requête et nous retrouverons l'appel exact.
Contacter le support