Appearance
Troubleshooting
Mon webhook n'arrive pas
Diagnostic
- Dashboard Webhooks Logs : la requête est-elle listée ?
- Non l'événement n'a pas été déclenché. Vérifiez que la transaction est passée en
success/failed/cancelled/expired. Forcez un pull avecPOST /v1/payments/{id}/verify. - Oui, avec
http_statusnon-2xx votre serveur a refusé. Allez à « Mon endpoint répond 4xx/5xx ». - Oui, avec
error_message: "timeout"votre serveur a dépassé 15 secondes. Allez à « Timeout ».
- Non l'événement n'a pas été déclenché. Vérifiez que la transaction est passée en
Mon endpoint répond 4xx/5xx
| http_status | Cause typique |
|---|---|
| 400 | Body parsing : votre serveur lit le payload avant la vérification de signature |
| 401 / 403 | Auth middleware bloque les requêtes externes exempter /webhooks/haybtech |
| 404 | Route mal configurée vérifier l'URL exacte dans le dashboard |
| 422 | Validation Laravel/middleware accepter le payload tel quel |
| 500 | Erreur applicative voir vos logs |
| 502 / 503 | Reverse-proxy down ou app non démarrée |
Solution : ajoutez route('webhooks.haybtech') à withoutMiddleware([VerifyCsrfToken::class]) (Laravel) ou exemptez du middleware d'auth.
Timeout
Votre handler doit répondre 2xx en moins de 15 secondes. Si vous avez du traitement long :
php
// Mauvais
public function webhook(Request $request) {
$this->processOrder($request); // 30 secondes
$this->sendEmail($request);
return response('ok');
}
// Bon
public function webhook(Request $request) {
ProcessHaybtechWebhookJob::dispatch($request->all());
return response('ok'); // immédiat
}Mon serveur reçoit le webhook 5 fois
Comportement normal c'est un retry. Causes :
- Vous répondez 2xx mais après plus de 15s HayBTech a déjà déclaré timeout
- Vous répondez non-2xx
- Vous répondez 2xx mais HayBTech ne reçoit pas la réponse (réseau)
Solution : implémentez l'idempotency côté votre serveur en stockant event_id (champ data.id du payload).
sql
CREATE UNIQUE INDEX uq_inbound_event ON your_webhook_log(event_id);Signature webhook invalide
Symptôme
Votre vérification HMAC échoue alors que vous utilisez le bon secret.
Cause #1 : body modifié avant vérification
Frameworks comme Express, Symfony, Laravel parsent le JSON automatiquement. Vous devez vérifier la signature sur le body brut avant tout parsing.
js
// Mauvais
app.use(express.json()) // parse JSON
app.post('/webhook', (req, res) => {
verify(req.body) // req.body est déjà un objet, pas le brut
})
// Bon
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
verify(req.body.toString()) // brut
const event = JSON.parse(req.body.toString())
})Cause #2 : encoding HMAC
Comparez les hex en lowercase des deux côtés (hash_hmac PHP retourne lowercase, vérifiez côté Node). Et utilisez hash_equals / crypto.timingSafeEqual pas ===.
Cause #3 : timestamp expiré
|now - t| > 300s est rejeté. Vérifiez l'heure de votre serveur (NTP). Si vous travaillez sur du replay manuel d'anciens webhooks, augmentez la tolérance ou repassez par le pull verify.
Idempotency-Key conflict
Symptôme
409 idempotency_conflict quand vous renvoyez la requête.
Diagnostic
bash
curl -X POST .../v1/payments \
-H "Idempotency-Key: abc-123" \
-d '{"amount":5000}'
# 201
curl -X POST .../v1/payments \
-H "Idempotency-Key: abc-123" \
-d '{"amount":5000,"description":"oops"}'
# 409 body différentSolution :
- Pour retry : même clé, exactement même body.
- Pour une nouvelle requête : nouvelle clé.
Bonne pratique
Générez la clé au moment où l'utilisateur clique "Payer", persistez-la côté client (localStorage / DB) jusqu'à la confirmation finale. Ne la regénérez pas à chaque retry HTTP.
Transaction bloquée en pending
Diagnostic
bash
curl -X POST https://app.haybtech.com/v1/payments/{id}/verify \
-H "Authorization: Bearer pk_test_xxx"Le pull verify va interroger le provider en aval et synchroniser le statut. Si le provider confirme, la transaction transite et un webhook part vers vous.
Si rien ne change
- Le canal de paiement est en incident : consultez la page de statut communiquée au support
- Le payeur n'a jamais finalisé l'OTP : la transaction expirera à
expires_at - La référence fournisseur est manquante côté HayBTech : contactez
support@haybtech.comavec la référence interne
Refund refusé : refund_not_supported
Certains canaux mobile money ne supportent pas le refund automatique. Procédure manuelle dans ce cas :
- Créer un payout vers le numéro du payeur d'origine
- Marquer la transaction d'origine comme remboursée via le dashboard
Les cartes supportent le refund automatique.
Le solde affiché ne correspond pas à mes settlements
| Composant | Inclus dans le solde affiché ? |
|---|---|
success non-settled | |
pending (en attente) | |
success déjà settled | |
| Refund émis | (déduit) |
| Chargeback en cours | (réservé sur un solde séparé) |
Le solde "disponible" diffère du solde "comptable". Le dashboard expose les deux.
Signature pk_live_ qui répond livemode_mismatch
Vous utilisez une clé live sur un objet créé avec une clé test (ou inversement). Solution : utilisez la clé du même mode (pk_test_ ↔ objet test, pk_live_ ↔ objet live). Les identifiants sont strictement scopés par livemode.
Problèmes de connexion API (SSL, Timeout, etc.)
Erreur SSL : SSL certificate problem: unable to get local issuer certificate
Cette erreur survient généralement sur les serveurs Windows ou les installations PHP/CURL anciennes qui n'ont pas de certificat CA à jour.
Solution :
- Téléchargez le fichier
cacert.pemofficiel sur curl.se/ca/cacert.pem. - Dans votre
php.ini, configurez le chemin :inicurl.cainfo = "C:/chemin/vers/votre/cacert.pem" openssl.cafile = "C:/chemin/vers/votre/cacert.pem" - Redémarrez votre serveur web.
Erreur : Connection Timeout
Si votre serveur n'arrive pas à joindre app.haybtech.com :
- Vérifiez votre pare-feu : Votre serveur doit pouvoir faire des requêtes sortantes sur le port 443 (HTTPS).
- DNS : Vérifiez que
app.haybtech.comest correctement résolu depuis votre serveur (ping app.haybtech.com). - Proxy : Si votre serveur utilise un proxy, assurez-vous de configurer les options du SDK correspondantes (ou utilisez les variables d'environnement
HTTP_PROXY).
Erreur : 401 Unauthorized (Clé invalide)
Si vous recevez une erreur 401 alors que vous avez copié votre clé :
- Vérifiez que vous utilisez bien la Clé Secrète (
sk_...) pour les appels backend, et non la Clé Publique (pk_...). - Vérifiez le Mode : une clé
sk_test_ne peut accéder qu'aux objets de test (et inversement poursk_live_). - Assurez-vous qu'aucun espace ou retour à la ligne n'a été copié par mégarde avec la clé.
Aller plus loin
- Support :
support@haybtech.com
