Aller au contenu principal

Webhooks

MabiPay envoie des notifications HTTP POST en temps réel à votre notifyUrl à chaque changement de statut.

URL de callback provider

Les providers envoient leurs notifications vers l'endpoint unifié :

POST /api/v1/webhooks/callback/:providerSlug

Exemple BPay : POST /api/v1/webhooks/callback/bpay

Cet endpoint est exclu de la documentation Swagger car il est réservé aux providers.

Structure du payload

{
"event": "payment.success",
"reference": "PAY-20240615-ABCD",
"merchantRef": "ORDER-001",
"status": "success",
"amount": 5000,
"currency": "XOF",
"timestamp": "2024-06-15T14:32:00.000Z",
"metadata": {}
}

Types d'événements

ÉvénementDéclencheur
payment.successPaiement confirmé et réussi
payment.failedPaiement échoué
payment.expiredDélai de paiement dépassé
payment.cancelledPaiement annulé par le client
payout.successVirement réussi
payout.failedVirement échoué

Vérification de signature

Chaque requête webhook inclut le header X-MabiPay-Signature (HMAC SHA-256).

import { verifyWebhookSignature } from "@mabipay/sdk";

const isValid = verifyWebhookSignature({
secret: process.env.MABIPAY_WEBHOOK_SECRET,
signature: req.headers["x-mabipay-signature"],
payload: req.body.toString(), // body brut non parsé
});

if (!isValid) throw new Error("Signature invalide");
Corps brut requis

Parsez le corps uniquement après avoir vérifié la signature. Utilisez express.raw() ou l'équivalent de votre framework.

Politique de retry

En cas d'échec (code HTTP ≠ 2xx ou timeout), MabiPay retente la livraison :

TentativeDélai
1Immédiat
21 minute
35 minutes
430 minutes
52 heures

Bonnes pratiques

  1. Répondre rapidement — retournez un 200 immédiatement et traitez en arrière-plan
  2. Idempotence — votre endpoint peut recevoir plusieurs fois le même événement
  3. Vérifier la signature — ne traitez jamais un webhook sans vérification HMAC
  4. Vérifier le statut via API — pour les paiements critiques, confirmez avec GET /payments/:ref
// ✅ Bonne pratique : réponse immédiate + traitement async
app.post("/webhooks", async (req, res) => {
res.status(200).json({ received: true }); // Répondre AVANT le traitement

await processWebhookAsync(req.body); // Traiter en arrière-plan
});