Intégration des Webhooks
Guide complet pour intégrer les webhooks Jèko dans votre application
Vous intégrez avec un agent de codage ?
Le serveur MCP donne cette documentation à votre agent, et son outil validate_webhook relit votre
endpoint : signature vérifiée sur le corps brut, traitement idempotent, réponse rapide.
Configuration initiale
1. Configurer l'URL du webhook
Pour configurer votre URL de webhook :
- Connectez-vous au Dashboard Business
- Naviguez vers Paramètres > API & Webhooks
- Entrez votre URL de webhook (doit être HTTPS)
- Copiez votre secret webhook (nécessaire pour vérifier les signatures)
Important : Votre endpoint webhook doit :
- Utiliser HTTPS
- Être accessible publiquement
- Retourner un code de statut HTTP 2xx (le délai d'attente est de 30 secondes, voir Comportement des webhooks)
Combien de webhooks par magasin
Un seul. Une URL par magasin, et une URL pour l'entreprise. Un second abonnement sur le même magasin est refusé.
Pour recevoir plusieurs types d'événements, gardez un seul abonnement et triez sur le contenu reçu. N'en créez pas un par type.
Une transaction peut quand même partir vers deux URL, car il y a deux niveaux :
| Portée | Reçoit |
|---|---|
| Entreprise | les transactions de tous vos magasins |
| Magasin | les transactions de ce magasin |
Si le magasin a son propre webhook, la transaction part vers les deux URL. Si c'est la même URL des deux côtés, elle n'est appelée qu'une fois.
Après 15 échecs consécutifs, un webhook est désactivé et ne reçoit plus rien. Le compteur repart à zéro dès qu'une livraison réussit, donc une panne courte ne le déclenche pas.
Un webhook désactivé ne se réactive pas tout seul, même une fois votre endpoint réparé. Supprimez-le et recréez-le depuis le Dashboard Business. Rien ne vous prévient : surveillez vos livraisons.
2. Créer votre endpoint webhook
Votre endpoint doit :
- Accepter les requêtes POST
- Vérifier la signature HMAC-SHA256
- Traiter le payload JSON
- Retourner un code HTTP 200 pour confirmer la réception
Structure du payload
TRANSACTION_COMPLETED est la transaction elle-même, sans enveloppe ni champ event :
{
"id": "txn_1234567890",
"amount": {
"amount": 10000,
"currency": "XOF"
},
"fees": {
"amount": 100,
"currency": "XOF"
},
"status": "success",
"counterpartLabel": "John Doe",
"counterpartIdentifier": "+2250701234567",
"paymentMethod": "wave",
"transactionType": "payment",
"businessName": "Ma Boutique",
"storeId": "01a0b1c2-d3e4-7f89-a0b1-c2d3e4f5a6b7",
"storeReference": "STORE-001",
"storeName": "Magasin Principal",
"description": "Payment for order #12345",
"executedAt": "2024-01-15 14:30:25",
"transactionDetails": {
"id": "d22c81f3-ee04-4ec5-8bd2-cd8af5dabcfc",
"reference": "PAY-2024-001",
"paymentLinkId": "abc123def456"
}
}Les autres valeurs de Jeko-Event ont un autre corps. Voir Événements. Un Service Provider crée son abonnement avec Webhooks marchand, pas depuis cet écran.
Quand le webhook transaction est envoyé
TRANSACTION_COMPLETED est envoyé lorsque :
- Une transaction de paiement est complétée avec succès
- Une transaction de transfert est complétée avec succès
- Une transaction de transfert échoue
Champs du payload
| Champ | Type | Description |
|---|---|---|
id | string | Identifiant unique de la transaction |
amount | MoneyModel | Montant de la transaction |
fees | MoneyModel | Frais de la transaction |
status | string | Statut de la transaction (pending, success ou error) |
counterpartLabel | string | Nom du contrepartie (client ou bénéficiaire) |
counterpartIdentifier | string | Identifiant du contrepartie (numéro de téléphone, etc.) |
paymentMethod | string | Méthode de paiement utilisée (wave, orange, mtn, moov, djamo, bank) |
transactionType | string | Type de transaction (payment ou transfer) |
businessName | string | Nom de l'entreprise |
storeId | string | Identifiant du magasin où la transaction a eu lieu |
storeReference | string | Référence du magasin, celle que vous lui avez donnée |
storeName | string | Nom du magasin |
description | string | Description de la transaction |
executedAt | string | Date d'exécution de la transaction, au format YYYY-MM-DD HH:mm:ss |
transactionDetails | object | Détails supplémentaires de la transaction |
transactionDetails.id | string? | ID de la demande de paiement ou du transfert (optionnel) |
transactionDetails.reference | string? | Référence de la transaction (optionnel) |
transactionDetails.paymentLinkId | string? | ID du lien de paiement si applicable (optionnel) |
walletAvailableBalance | MoneyModel? | Solde disponible du portefeuille après l'opération (optionnel) |
Types de transactions
Le champ transactionType vaut "payment" pour un encaissement et "transfer" pour un reversement. Ce sont les deux seules valeurs qu'un webhook porte, puisque ce sont les deux seuls types de transaction qui en déclenchent un.
Statuts de transaction
Le champ status indique le statut :
"pending": Transaction en cours de traitement"success": Transaction réussie"error": Transaction échouée
Vérification de la signature
Tous les webhooks sont signés avec HMAC-SHA256. Vous devez vérifier la signature pour authentifier la requête.
Algorithme de vérification
L'en-tête Jeko-Signature contient le HMAC-SHA256 du corps brut, encodé en hexadécimal minuscule, sans préfixe ni horodatage : a3f5c9…, et rien d'autre.
- Récupérez l'en-tête
Jeko-Signature - Calculez le HMAC-SHA256 du corps de la requête (raw body) avec votre secret webhook
- Comparez la signature calculée avec celle reçue
Important : Utilisez le corps de la requête brut (raw body), pas le JSON parsé.
Exemples d'intégration
Consultez Exemples de code pour des implémentations complètes dans différents langages.
Bonnes pratiques
- Vérifiez toujours la signature : Ne traitez jamais un webhook sans vérifier sa signature
- Idempotence : Traitez les webhooks de manière idempotente (évitez les traitements en double)
- Réponse rapide : Accusez réception sans attendre la fin de votre traitement. Le délai d'attente est de 30 secondes, au-delà le webhook est réessayé
- Logging : Enregistrez tous les webhooks reçus pour le débogage
- Gestion d'erreurs : Gérez les erreurs gracieusement et retournez toujours un code HTTP approprié
Consultez Bonnes pratiques pour plus de détails.