Webhooks
Exemples de code Webhooks
Exemples d'implémentation de webhooks Jèko dans différents langages
Vue d'ensemble
Cette page contient des exemples complets d'implémentation de webhooks Jèko dans différents langages. Tous les exemples incluent :
- Vérification de la signature HMAC-SHA256
- Parsing du payload
- Traitement des événements
- Gestion d'erreurs
Serveur webhook
Le même serveur, dans quatre langages. Choisissez votre onglet.
const express = require('express');
const crypto = require('crypto');
const app = express();
// Middleware pour parser le body brut (important pour la vérification de signature)
app.use('/webhook', express.raw({ type: 'application/json' }));
const WEBHOOK_SECRET = process.env.JEKO_WEBHOOK_SECRET;
function verifySignature(rawBody, signature) {
const expectedSignature = crypto
.createHmac('sha256', WEBHOOK_SECRET)
.update(rawBody)
.digest('hex');
const received = Buffer.from(signature);
const expected = Buffer.from(expectedSignature);
// timingSafeEqual lève une exception si les longueurs diffèrent, ce qui est
// justement le cas d'une signature falsifiée : comparer les tailles d'abord.
if (received.length !== expected.length) return false;
return crypto.timingSafeEqual(received, expected);
}
app.post('/webhook', async (req, res) => {
try {
// Vérifier la signature
const signature = req.headers['jeko-signature'];
if (!signature || !verifySignature(req.body, signature)) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Le payload est la transaction elle-même, sans enveloppe
const transaction = JSON.parse(req.body.toString());
// Accuser réception avant de traiter
res.status(200).json({ received: true });
await handleTransaction(transaction);
} catch (error) {
console.error('Webhook error:', error);
// Le 200 est déjà parti avant le traitement : répondre à nouveau lèverait
// ERR_HTTP_HEADERS_SENT. On journalise, et on rejoue de son côté.
if (!res.headersSent) {
res.status(500).json({ error: 'Internal server error' });
}
}
});
async function handleTransaction(transaction) {
console.log('Transaction:', transaction.id);
console.log('Type:', transaction.transactionType);
console.log('Status:', transaction.status); // "pending", "success" ou "error"
console.log('Amount:', transaction.amount);
console.log('Fees:', transaction.fees);
console.log('Store:', transaction.storeName);
console.log('Business:', transaction.businessName);
console.log('Executed at:', transaction.executedAt); // "2024-01-15 14:30:25"
// Détails de la transaction (champs optionnels)
const details = transaction.transactionDetails ?? {};
if (details.id) console.log('Payment request ID:', details.id);
if (details.reference) console.log('Reference:', details.reference);
if (details.paymentLinkId) console.log('Payment Link ID:', details.paymentLinkId);
if (transaction.status === 'success') {
console.log('Transaction réussie:', transaction.id);
console.log('Contrepartie:', transaction.counterpartLabel);
console.log('Identifiant:', transaction.counterpartIdentifier);
// Mettre à jour votre base de données, envoyer une confirmation, etc.
} else if (transaction.status === 'error') {
console.log('Transaction échouée:', transaction.id);
// Gérer l'échec, notifier l'utilisateur, etc.
}
}
app.listen(3000, () => {
console.log('Webhook server listening on port 3000');
});Test avec cURL
# Exemple de test local avec ngrok
# 1. Démarrer votre serveur local
# 2. Exposer avec ngrok: ngrok http 3000
# 3. Configurer l'URL ngrok dans le Dashboard Business
# Test manuel du webhook
curl -X POST http://localhost:3000/webhook \
-H "Content-Type: application/json" \
-H "Jeko-Signature: your_test_signature" \
-d '{
"id": "txn_test123",
"amount": {
"amount": 10000,
"currency": "XOF"
},
"fees": {
"amount": 100,
"currency": "XOF"
},
"status": "success",
"counterpartLabel": "John Doe",
"counterpartIdentifier": "+2250701234567",
"paymentMethod": "wave",
"transactionType": "PaymentRequest",
"businessName": "Ma Boutique",
"storeName": "Magasin Principal",
"description": "Test payment",
"executedAt": "2024-01-15 14:30:25",
"transactionDetails": {
"id": "d22c81f3-ee04-4ec5-8bd2-cd8af5dabcfc",
"reference": "TEST-001",
"paymentLinkId": "abc123def456"
}
}'Points importants
- Body brut : Utilisez toujours le body brut (raw body) pour calculer la signature, pas le JSON parsé
- Comparaison sécurisée : Utilisez une comparaison sécurisée (timing-safe) pour éviter les attaques par timing
- Réponse rapide : Accusez réception sans attendre la fin du traitement. Au-delà de 5 secondes, le webhook est réessayé
- Traitement asynchrone : Pour les traitements longs, acceptez le webhook immédiatement et traitez-le en arrière-plan
- Idempotence : Assurez-vous que le traitement est idempotent pour éviter les doublons