Les webhooks sont le cœur de toute intégration de paiement sérieuse. C'est le mécanisme par lequel MonCashConnect notifie votre serveur qu'un paiement a été confirmé. Mal implémentés, ils peuvent être la source de fraudes ou de doubles crédits. Bien implémentés, ils rendent votre système fiable et automatique.
Comment fonctionnent les webhooks MonCashConnect
Quand un utilisateur complète un paiement MonCash, notre infrastructure envoie une requête HTTP POST à l'URL webhook que vous avez configurée. Cette requête contient les détails du paiement en JSON et une signature cryptographique HMAC-SHA256 dans le header X-MonCashConnect-Signature.
Configurer votre URL webhook
- 1.Dans votre Dashboard MonCashConnect, allez dans Developer → Projets
- 2.Cliquez sur votre projet, puis « Configurer le webhook »
- 3.Entrez l'URL HTTPS de votre endpoint (ex: https://votresite.com/webhook/moncash)
- 4.Copiez le secret webhook généré — vous en aurez besoin pour vérifier les signatures
- 5.Sauvegardez et testez avec le bouton « Envoyer un événement test »
Structure d'un événement webhook
{
"id": "evt_01J5K8...",
"type": "payment.completed",
"createdAt": "2026-05-06T14:23:11Z",
"data": {
"transactionId": "txn_01J5K8...",
"orderId": "CMD-00123",
"amount": 2500,
"currency": "HTG",
"status": "completed",
"payer": {
"phone": "509XXXXXXXX"
}
}
}Vérifier la signature HMAC (obligatoire)
Ne traitez jamais un webhook sans vérifier sa signature. N'importe qui peut envoyer une requête POST à votre URL — seule la vérification cryptographique garantit que l'événement provient bien de MonCashConnect.
import crypto from "node:crypto";
// Récupérer le raw body — IMPORTANT: ne pas parser en JSON avant
app.post("/webhook/moncash",
express.raw({ type: "application/json" }),
(req, res) => {
const sig = req.headers["x-moncashconnect-signature"];
const secret = process.env.WEBHOOK_SECRET;
const hmac = crypto
.createHmac("sha256", secret)
.update(req.body) // req.body doit être un Buffer
.digest("hex");
if (!crypto.timingSafeEqual(Buffer.from(hmac), Buffer.from(sig))) {
return res.status(401).json({ error: "Signature invalide" });
}
const event = JSON.parse(req.body.toString());
await handleEvent(event);
res.sendStatus(200);
}
);import hmac, hashlib, os
from flask import Flask, request, abort
app = Flask(__name__)
@app.route("/webhook/moncash", methods=["POST"])
def webhook():
sig = request.headers.get("X-MonCashConnect-Signature", "")
secret = os.environ["WEBHOOK_SECRET"].encode()
expected = hmac.new(secret, request.data, hashlib.sha256).hexdigest()
if not hmac.compare_digest(expected, sig):
abort(401)
event = request.get_json()
handle_event(event)
return "", 200Gestion des erreurs et retries
MonCashConnect retente les webhooks échoués (réponse non-200 ou timeout) selon un backoff exponentiel : 5s, 30s, 2min, 10min, 1h. Après 5 tentatives sans succès, l'événement est marqué comme échoué et vous recevez une notification email.
- Toujours retourner HTTP 200 dès réception, même si le traitement est asynchrone
- Stocker les event.id pour détecter les doublons (retries)
- Traiter les webhooks de manière idempotente — deux appels avec le même orderId ne doivent pas doubler le crédit
- Timeout recommandé de votre endpoint : < 5 secondes
- Surveiller les échecs dans Dashboard → Developer → Webhook Logs
Tester en local avec un tunnel
# Exposer votre localhost avec ngrok
npx ngrok http 3000
# L'URL générée (ex: https://abc123.ngrok.io) peut être configurée
# comme URL webhook temporaire dans votre dashboard pour les testsLes logs webhook de MonCashConnect conservent les 100 derniers événements avec leur payload et statut. Consultez la documentation complète pour tous les types d'événements.
Lire la documentation webhook →