Événements webhook : gérer les notifications de paiement en temps réel

Événements webhook : gérer les notifications de paiement en temps réel

Table des matières

Les paiements sont par nature asynchrones. Une transaction par carte que vous lancez peut réussir immédiatement, ou rester en attente, nécessiter une authentification 3DS, déclencher une revue antifraude, ou entraîner une rétrofacturation des jours plus tard. Si votre application ne réagit qu'à la réponse API synchrone au moment de la création d'une transaction, vous manquerez une grande partie des événements du cycle de vie du paiement qui affectent votre logique métier, l'expérience client et la réconciliation financière.

Les webhooks sont le mécanisme de TIB Finance pour transmettre des notifications d'événements en temps réel à votre application dès qu'un fait important survient. Ce guide couvre tout ce qu'il faut savoir pour implémenter un gestionnaire de webhook robuste et sécurisé. Pour un contexte plus large sur l'intégration API, consultez le guide d'intégration de l'API de paiement.

Que sont les webhooks?

Un webhook est une requête HTTP POST envoyée par TIB Finance vers une URL que vous spécifiez (votre point de terminaison webhook) lorsqu'un événement précis se produit. Voyez-le comme TIB Finance qui appelle votre application pour dire « quelque chose vient de se produire, voici les détails ».

L'alternative, l'interrogation périodique (polling), consiste à faire appeler votre application de façon répétée à l'API de TIB Finance pour demander « est-ce que quelque chose a changé? ». L'interrogation périodique est inefficace, ajoute de la latence à votre traitement des événements et crée une charge API inutile. Les webhooks éliminent ces trois problèmes en livrant les événements au moment où ils surviennent.

Configurer votre point de terminaison webhook

Configurez l'URL de votre point de terminaison webhook dans le tableau de bord marchand de TIB Finance, sous Paramètres > Webhooks. Votre point de terminaison doit :

  • Être accessible publiquement via HTTPS (pas HTTP)
  • Accepter les requêtes HTTP POST
  • Retourner un code HTTP 200 (ou tout code 2xx) dans un délai de 10 secondes
  • Accepter le type de contenu application/json

Vous pouvez enregistrer plusieurs points de terminaison webhook et filtrer les types d'événements que chacun reçoit, par exemple en envoyant les événements de paiement à votre système de gestion des commandes et les événements de litige au système de votre équipe des finances.

Référence des types d'événements

TIB Finance envoie des webhooks pour les catégories d'événements suivantes :

Événements de paiement

Type d'événementDescription
payment.succeeded Un paiement a été traité avec succès et les fonds seront capturés. Déclenchez le traitement de la commande.
payment.failed Une tentative de paiement a été refusée ou a échoué. Avisez le client d'essayer une autre carte.
payment.pending Le paiement est en attente de traitement (par exemple, ACH, virement bancaire). Ne traitez pas la commande avant payment.succeeded.
payment.captured Un paiement préalablement autorisé (auth seulement) a été capturé.
payment.cancelled Un paiement autorisé a été annulé avant la capture.

Événements de remboursement

Type d'événementDescription
refund.created Un remboursement a été lancé. Mettez à jour vos registres, mais attendez refund.succeeded.
refund.succeeded Le remboursement a été traité avec succès et les fonds ont été retournés au client.
refund.failed Un remboursement n'a pas pu être traité. Une intervention manuelle peut être nécessaire.

Événements de litige

Type d'événementDescription
dispute.created Une rétrofacturation ou un litige a été déposé. Répondez avant la date limite.
dispute.updated Le statut d'un litige a changé (par exemple, une preuve a été soumise).
dispute.closed Un litige a été résolu. Vérifiez le champ de résultat pour savoir si vous avez gagné ou perdu.

Structure de la charge utile du webhook

Toutes les charges utiles de webhook de TIB Finance partagent une structure d'enveloppe commune :

{ "id": "evt_2Mc5pR7nQtL3wJ9v", // Identifiant unique de l'événement "type": "payment.succeeded", // Type d'événement "created_at": "2024-12-01T14:32:11Z", // Horodatage ISO 8601 "livemode": true, // false en sandbox "data": { "object": { "id": "txn_9Yc4oQ8nRsM3wL5z", "amount": 4999, "currency": "USD", "status": "succeeded", "reference": "ORDER-20241201-001", "payment_method": { "token": "pm_3Kd9fN7mQpJ2vH4x", "last4": "1111", "brand": "visa" } } } }

Utilisez toujours le champ id dans data.object pour récupérer l'objet faisant autorité depuis l'API si vous avez besoin de détails complets et à jour. Ne vous fiez pas aux données mises en cache provenant d'appels API antérieurs.

Vérification de signature

Chaque requête webhook de TIB Finance inclut un en-tête HTTP TIB-Signature contenant une signature HMAC-SHA256 du corps de la requête, signée avec votre secret webhook. Vérifiez toujours cette signature avant de traiter l'événement. Ignorer la vérification de signature expose votre application aux attaques par rejeu et aux événements falsifiés.

Critique pour la sécurité

Si vous traitez un webhook sans vérifier la signature, un attaquant pourrait envoyer un faux événement « payment.succeeded » à votre point de terminaison et déclencher le traitement d'une commande sans qu'aucun paiement réel n'ait eu lieu. La vérification de signature n'est pas négociable.

// Exemple de vérification de signature en Node.js const crypto = require('crypto'); function verifyWebhookSignature(payload, signature, secret) { // Le format de l'en-tête de signature est : t=timestamp,v1=signature const parts = signature.split(','); const timestamp = parts[0].split('=')[1]; const receivedSig = parts[1].split('=')[1]; // Vérifie que l'horodatage est dans un délai de 5 minutes pour prévenir les attaques par rejeu const tolerance = 300; // 5 minutes en secondes if (Math.abs(Date.now() / 1000 - parseInt(timestamp)) > tolerance) { throw new Error('Webhook timestamp too old'); } // Calcule la signature attendue const signedPayload = `${timestamp}.${payload}`; const expectedSig = crypto .createHmac('sha256', secret) .update(signedPayload) .digest('hex'); // Utilise une comparaison à temps constant pour prévenir les attaques temporelles return crypto.timingSafeEqual( Buffer.from(receivedSig), Buffer.from(expectedSig) ); }

Logique de nouvelle tentative

TIB Finance relance automatiquement la livraison des webhooks lorsque votre point de terminaison ne retourne pas de réponse 2xx. Comprendre l'échéancier des nouvelles tentatives vous aide à concevoir une gestion des erreurs robuste :

  • Nouvelle tentative immédiate : si votre point de terminaison retourne une erreur 5xx ou dépasse le délai, TIB Finance relance après 30 secondes.
  • Délai exponentiel : les tentatives suivantes utilisent un délai exponentiel : 1 minute, 5 minutes, 30 minutes, 2 heures, 8 heures, 24 heures.
  • Nombre maximal de tentatives : TIB Finance tentera la livraison jusqu'à 10 fois sur environ 72 heures.
  • Abandon : après 10 tentatives échouées, l'événement est marqué comme échoué. Vous pouvez consulter et relancer manuellement les événements échoués depuis le tableau de bord marchand.

Concevez votre gestionnaire de webhook pour qu'il retourne 200 immédiatement à la réception, avant tout traitement complexe. Accusez d'abord réception, puis traitez de façon asynchrone à l'aide d'une file d'attente ou d'une tâche en arrière-plan. Cela évite les délais dépassés qui entraînent des nouvelles tentatives inutiles.

// Modèle correct : accuser réception d'abord, traiter de façon asynchrone app.post('/webhook', (req, res) => { // Vérifier la signature en premier const isValid = verifyWebhookSignature( req.rawBody, req.headers['tib-signature'], process.env.WEBHOOK_SECRET ); if (!isValid) return res.status(401).send('Invalid signature'); // Accuser réception immédiatement res.status(200).send('OK'); // Traiter de façon asynchrone (mettre l'événement en file d'attente) eventQueue.push(req.body); });

Idempotence

En raison du mécanisme de nouvelle tentative, votre gestionnaire de webhook doit être idempotent : traiter le même événement plusieurs fois doit produire le même résultat que le traiter une seule fois. Sans idempotence, les événements relancés peuvent causer des traitements de commande en double, des envois de courriels en double ou des registres financiers incorrects.

Implémentez l'idempotence en suivant les identifiants d'événements déjà traités :

async function processWebhookEvent(event) { // Vérifier si cet événement a déjà été traité const existing = await db.processedEvents.findOne({ event_id: event.id }); if (existing) { console.log(`Event ${event.id} already processed, skipping`); return; } // Traiter l'événement if (event.type === 'payment.succeeded') { await fulfillOrder(event.data.object.reference); await sendConfirmationEmail(event.data.object); } // Marquer comme traité APRÈS un traitement réussi await db.processedEvents.insert({ event_id: event.id, processed_at: new Date() }); }

Meilleures pratiques

Un résumé des recommandations clés pour une implémentation de webhook de qualité production :

  1. Vérifiez toujours les signatures. Rejetez tout webhook qui échoue la vérification de signature avec un code HTTP 401.
  2. Répondez dans un délai de 10 secondes. Accusez d'abord réception, puis traitez de façon asynchrone à l'aide d'une file d'attente de tâches.
  3. Implémentez l'idempotence. Conservez les identifiants d'événements traités et ignorez les doublons.
  4. Utilisez uniquement HTTPS. Ne configurez jamais un point de terminaison webhook sur une URL HTTP.
  5. Récupérez des données à jour depuis l'API. Si vous avez besoin des détails complets d'un objet, récupérez-les via l'API à l'aide de l'identifiant de l'objet dans l'événement, plutôt que de vous fier uniquement à la charge utile du webhook.
  6. Surveillez les échecs. Configurez des alertes pour les livraisons de webhook échouées, en particulier pour les événements critiques comme payment.succeeded et dispute.created.
  7. Testez dans le sandbox. Le sandbox de TIB Finance vous permet de déclencher manuellement n'importe quel type d'événement pour tester votre gestionnaire. Consultez le guide de test sandbox.
  8. Gérez tous les types d'événements avec élégance. Votre gestionnaire recevra des types d'événements que vous n'avez peut-être pas explicitement gérés. Ayez toujours un cas par défaut qui retourne 200 pour éviter des nouvelles tentatives inutiles pour les événements que vous ignorez intentionnellement.
  9. Journalisez tout. Journalisez la charge utile brute, le résultat de la vérification de signature et le résultat de votre traitement pour chaque webhook reçu. C'est essentiel pour le débogage et la réconciliation financière.
  10. Utilisez des points de terminaison distincts par environnement. N'envoyez jamais de webhooks de production vers un point de terminaison de développement ou de staging, et vice-versa.

Construisez votre intégration webhook

Le sandbox de TIB Finance vous permet de tester tous les types d'événements webhook avant la mise en production. Accédez à la documentation développeur et à l'environnement sandbox pour commencer.

Documentation API Sandbox