Un client paie, Stripe déclenche un événement payment_intent.succeeded sur votre backend, et votre endpoint est censé marquer la commande comme payée. Cette dernière étape est celle qui échoue silencieusement. Le webhook arrive, votre gestionnaire lève une exception, et personne ne le remarque avant qu'un ticket de support n'indique « J'ai payé mais mon compte affiche toujours impayé. » Vous voulez un test en CI qui prouve que l'événement est arrivé et a été traité correctement, à chaque déploiement.
Le problème est qu'un webhook est un appel HTTP entrant de Stripe vers vous, et non une requête que vous effectuez. La plupart des outils de test d'API sont conçus pour envoyer une requête et vérifier la réponse, ce qui est la forme opposée. La question devient donc : comment vérifier quelque chose qui arrive selon son propre calendrier, au sein d'une exécution de CI, sans surveillance humaine ? Ce guide présente la manière honnête et prise en charge de le faire avec Apidog, et il commence par une limitation que vous devez connaître dès le départ. Si vous souhaitez d'abord avoir une vue d'ensemble du test des endpoints basés sur les événements, notre guide sur la façon de tester les webhooks prépare le terrain, et la documentation de Stripe sur les webhooks couvre le modèle de livraison des événements.
La contrainte à prendre en compte
Voici le fait fondamental, clairement énoncé dans la propre documentation d'Apidog : « Apidog ne prend pas nativement en charge l'écoute des webhooks. » Apidog ne se positionne pas sur une URL publique pour intercepter les appels entrants de Stripe en temps réel. Si vous espériez pointer Stripe vers un écouteur Apidog et voir les événements arriver, cette voie n'existe pas.
Cela ressemble à une impasse. Ce n'en est pas une. Cela change simplement la forme du test. Au lieu d'intercepter le webhook à son arrivée, vous le capturez dans votre propre backend, le stockez, puis Apidog interroge cet enregistrement stocké et le valide. Capturer d'abord, valider ensuite. Une fois que vous acceptez cette séparation, l'ensemble du workflow devient simple et, surtout, il s'intègre parfaitement à la CI car une requête de base de données est déterministe et reproductible.
À quoi ressemble le modèle "capturer puis interroger"
Le modèle recommandé par la documentation d'Apidog comporte quatre éléments :
- Créez un endpoint dans votre service backend pour capturer les webhooks Stripe entrants.
- Stockez les données d'événement du webhook dans une table
Stripe event logsde votre base de données. - Utilisez le processeur Post-Request d'Apidog pour interroger votre base de données.
- Récupérez l'événement webhook stocké et validez-le par rapport aux résultats attendus.
Deux de ces étapes se trouvent dans votre code, et deux dans Apidog. L'endpoint de capture et la table de journalisation sont de votre responsabilité à construire, car ils s'exécutent au sein de votre propre application. Le travail d'Apidog commence une fois que l'événement est dans votre base de données : il se connecte à cette base de données et lit la ligne pour confirmer que l'événement a été traité comme vous l'attendez. Gardez cette division claire et le reste se mettra en place.
Étape 1 : construire l'endpoint de capture
Votre backend a besoin d'une route vers laquelle Stripe peut effectuer une requête POST. Il s'agit de code d'application ordinaire, et non d'une fonctionnalité Apidog. Un gestionnaire Express minimal qui vérifie la signature et journalise l'événement ressemble à ceci :
import express from "express";
import Stripe from "stripe";
const app = express();
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
const endpointSecret = process.env.STRIPE_WEBHOOK_SECRET;
app.post(
"/webhooks/stripe",
express.raw({ type: "application/json" }),
async (req, res) => {
let event;
try {
event = stripe.webhooks.constructEvent(
req.body,
req.headers["stripe-signature"],
endpointSecret
);
} catch (err) {
return res.status(400).send(`Signature check failed: ${err.message}`);
}
// Persistez l'événement afin qu'un test puisse le relire plus tard.
await db.query(
`INSERT INTO stripe_event_logs (event_id, type, payload, handled_at)
VALUES ($1, $2, $3, now())
ON CONFLICT (event_id) DO NOTHING`,
[event.id, event.type, JSON.stringify(event.data.object)]
);
if (event.type === "payment_intent.succeeded") {
const intent = event.data.object;
await markOrderPaid(intent.metadata.order_id);
}
res.json({ received: true });
}
);
Deux choses sont importantes ici. Premièrement, vous vérifiez la signature Stripe avec constructEvent avant de faire confiance à quoi que ce soit, ce qui est l'étape de sécurité non négociable pour tout récepteur de webhook. Si vous voulez comprendre le raisonnement complet derrière cette vérification, notre tutoriel sur la vérification de signature de webhook explique pourquoi une comparaison du corps brut est la seule méthode sûre. Deuxièmement, vous écrivez l'événement dans une table Stripe event logs. Cette ligne est ce qu'Apidog lira. La clause ON CONFLICT DO NOTHING rend le journal idempotent, car Stripe peut livrer le même événement plus d'une fois.
Étape 2 : connecter votre base de données dans l'environnement Apidog
Apidog prend en charge la connexion à une base de données dans l'environnement correspondant, et cette connexion est ce qui rend ce modèle fonctionnel. Configurez une connexion à la base de données pour l'environnement ciblé par votre exécution CI, qu'il s'agisse d'un Postgres de staging ou d'une base de données de test dédiée. Une fois la connexion établie, une étape de test peut exécuter du SQL et récupérer des lignes réelles.
Faites correspondre la connexion à l'environnement que vous testez. Un test qui s'exécute sur un environnement de staging doit interroger la base de données de staging, de sorte que l'événement déclenché par votre test soit l'événement lu par votre test. Des environnements mal assortis sont la raison la plus courante pour laquelle un endpoint de capture fonctionnel échoue toujours à l'assertion.
Étape 3 : ajouter un processeur Post-Request pour interroger le journal
C'est le cœur du processus. Le Post-Request Processor est la fonctionnalité Apidog qui interroge votre base de données et valide l'événement webhook enregistré à l'intérieur d'un test. Vous l'attachez à une requête dans votre scénario de test. Après l'exécution de la requête, le processeur exécute votre SQL, lit l'événement stocké et vous permet d'effectuer une assertion sur le résultat.
Un flux réaliste pour le cas payment_intent.succeeded :
- Votre scénario de test déclenche le paiement. Il peut s'agir d'une requête qui crée une intention de paiement et la confirme en mode test Stripe, ou d'une fixture qui déclenche un événement de test connu sur votre endpoint de capture.
- Stripe livre le webhook à votre route
/webhooks/stripe, qui vérifie la signature et écrit une ligne dansstripe_event_logs. - Un
Post-Request Processorà l'étape suivante interroge cette table pour l'événement.
La requête exécutée par le processeur est du SQL pur :
SELECT event_id, type, payload, handled_at
FROM stripe_event_logs
WHERE type = 'payment_intent.succeeded'
ORDER BY handled_at DESC
LIMIT 1;
Vous effectuez ensuite une assertion sur la ligne renvoyée. Le test réussit lorsque les données journalisées correspondent à vos attentes : le type est payment_intent.succeeded, l'event_id correspond à celui que vous avez déclenché, le montant du payload est égal à ce que vous avez facturé, et handled_at est renseigné, ce qui prouve que votre gestionnaire a réellement fonctionné plutôt que la ligne n'étant qu'un espace réservé. Récupérez l'événement webhook stocké, comparez-le au résultat attendu et laissez l'assertion décider du succès ou de l'échec.
Étant donné que la livraison des webhooks n'est pas instantanée, laissez à l'événement un instant pour arriver avant de l'interroger. Une courte étape de délai, ou une boucle de sondage qui réessaie la requête plusieurs fois avant d'échouer, empêche le test de courir contre la livraison de Stripe. C'est le seul endroit où la nature asynchrone des webhooks se répercute sur la conception de vos tests, et une petite fenêtre de réessai la gère proprement.
Une note sur le transfert en temps réel pendant le développement local
Le modèle "capturer puis interroger" est conçu pour la CI, où une base de données et un enregistrement stocké sont exactement ce que vous voulez. Le développement local est une situation différente. Lorsque vous écrivez le gestionnaire sur votre ordinateur portable, Stripe ne peut pas atteindre directement localhost, vous avez donc besoin de quelque chose pour transférer les événements vers votre machine en temps réel.
Pour cela, la documentation d'Apidog renvoie à un service de relais de webhook, citant la CLI Stripe et Ngrok comme exemples. La CLI Stripe peut écouter et transférer les événements directement vers votre port local :
stripe listen --forward-to localhost:3000/webhooks/stripe
Cela vous donne des événements en direct pendant que vous construisez le gestionnaire. Ngrok fait le même travail en exposant votre port local sur une URL publique que vous enregistrez comme endpoint Stripe. Utilisez-les pour le cycle de développement interne, puis fiez-vous à la base de données et au flux du Post-Request Processor pour les assertions qui s'exécutent dans votre pipeline. Les deux sont complémentaires : le relais pour la construction, la capture-puis-l'interrogation pour la preuve.
Ne confondez pas cela avec la fonctionnalité Webhook native d'Apidog
Apidog dispose d'une fonctionnalité littéralement appelée Webhook, et il est facile de supposer que c'est ainsi que vous interceptez les événements Stripe. Ce n'est pas le cas, et les confondre vous coûtera un après-midi. La fonctionnalité native Webhook sert à définir et documenter un webhook sortant, c'est-à-dire un endpoint HTTP que votre propre système appelle lorsqu'un événement se produit. Le système initie l'appel vers une URL externe, ce qui est l'opposé d'un endpoint régulier où les clients vous appellent. Elle est utilisée pour décrire les notifications de changement d'état et les résultats de tâches asynchrones dans la documentation de votre API, et non pour recevoir les appels entrants de Stripe.
Si vous souhaitez documenter l'un de vos propres webhooks sortants, le flux est court :
- Cliquez sur l'icône
+dans la barre latérale gauche. - Sélectionnez
New Other Protocol APIs, puisWebhook. - Remplissez les champs requis :
Request Method(généralement POST), unWebhook Name, uneDebug URLfacultative pour les tests uniquement, etOther Infopour le corps de la requête, les en-têtes et la configuration. - Cliquez sur
Save.
Pour l'essayer, saisissez une URL dans le champ Debug URL et cliquez sur Send pour simuler l'appel du webhook. Une mise en garde à retenir : la Debug URL est uniquement destinée aux tests et n'apparaîtra pas dans votre documentation publiée ni dans votre exportation OpenAPI. Pour un traitement plus complet de la conception et de la documentation des rappels d'événements, notre article sur les webhooks dans la conception d'API explique où ils s'inscrivent. La version courte pour cet article : la fonctionnalité native Webhook définit vos événements sortants, et le modèle "capturer puis interroger" valide les événements entrants de Stripe. Gardez les deux dans des catégories mentales distinctes.
Variations et durcissement
Une fois que l'assertion de base fonctionne, quelques améliorations la rendent prête pour la production. Premièrement, affirmez plus que le type d'événement. Vérifiez l'event_id de bout en bout afin de savoir que l'événement exact que vous avez déclenché est celui que vous avez validé, et non un reste d'une exécution précédente. Tronquez ou délimitez la table stripe_event_logs par exécution de test si les événements s'accumulent.
Deuxièmement, testez les chemins d'échec. Déclenchez un événement que votre gestionnaire devrait rejeter, une mauvaise signature ou un type inattendu, et affirmez qu'aucun horodatage handled_at n'est écrit. Une suite de tests de webhook qui ne vérifie que le chemin heureux passe à côté des cas qui vous réveillent réellement à 2 heures du matin. Nos notes sur les meilleures pratiques pour les webhooks de paiement couvrent l'idempotence et le comportement de réessai qu'il convient d'intégrer à ces tests.
Troisièmement, maintenez l'assertion liée au sens métier, et pas seulement à la livraison. « L'événement est arrivé » est plus faible que « la commande est passée au statut payé ». Si votre gestionnaire met à jour une table orders, ajoutez une deuxième requête qui confirme que l'état en aval a changé, afin que le test prouve toute la chaîne et pas seulement l'écriture du journal.
Vous pouvez également aller au-delà de la porte de fusion. Une fois le scénario enregistré dans Apidog, planifiez son exécution à un rythme régulier afin qu'un gestionnaire de webhook défaillant soit détecté même entre les déploiements. Notre guide sur la planification des tests d'API dans Apidog montre comment appliquer cette même validation à l'aide d'un minuteur.
Automatisez le workflow avec l'Apidog CLI
Tout ce qui précède porte ses fruits lorsqu'il s'exécute sans surveillance, et c'est là qu'intervient l'Apidog CLI. Il s'agit intrinsèquement d'une histoire de CI, donc intégrer le scénario enregistré dans votre pipeline est la finition naturelle. Installez la CLI et authentifiez-vous avec votre jeton :
npm install -g apidog-cli
apidog login --with-token <YOUR_ACCESS_TOKEN>
Ensuite, exécutez votre scénario de validation de webhook enregistré en mode sans tête (headless) contre l'environnement dont la base de données contient les journaux d'événements :
apidog run --access-token $APIDOG_ACCESS_TOKEN -t <SCENARIO_ID> -e <ENV_ID> -r cli
Ici, -t est l'ID du scénario de test, -e est l'ID de l'environnement, et -r sélectionne le rapporteur. Utilisez -r html,cli si vous souhaitez un rapport consultable en plus de la sortie console pour vos artefacts CI. Le scénario contient le Post-Request Processor et sa requête de base de données, donc une seule commande déclenche le flux, lit la ligne stripe_event_logs et renvoie un code de sortie non nul si l'assertion échoue, ce qui est exactement ce dont un pipeline a besoin pour bloquer une fusion. Le guide d'installation de l'Apidog CLI couvre la configuration des jetons, et notre tutoriel sur le pipeline CI/CD montre l'intégration complète de GitHub Actions autour de cette commande.
Foire aux questions
Apidog peut-il recevoir un webhook Stripe directement ? Non. La documentation d'Apidog indique clairement qu'il « ne prend pas nativement en charge l'écoute des webhooks. » Vous capturez l'événement dans votre propre endpoint backend, le stockez dans une base de données, et Apidog le relit avec un Post-Request Processor. Pour le transfert en temps réel pendant le développement local, utilisez plutôt un relais comme la CLI Stripe ou Ngrok.
Où les assertions se produisent-elles réellement ? À l'intérieur de l'étape Post-Request Processor sur une requête de votre scénario de test. Il interroge votre table Stripe event logs via la connexion à la base de données que vous avez configurée dans l'environnement, récupère l'événement stocké et le compare à vos valeurs attendues. Le test réussit lorsque les données enregistrées correspondent.
Ai-je besoin d'un plan payant pour le flux de validation de base de données ? La documentation d'Apidog pour ce workflow ne mentionne aucune restriction de plan, ce guide n'en inventera donc pas. La réponse honnête est de vérifier les détails des plans actuels sur la page de tarification. Vous pouvez Télécharger Apidog et configurer un projet de test pour voir le Post-Request Processor et la connexion à la base de données d'environnement par vous-même.
Comment gérer le délai entre le déclenchement et la livraison ? La livraison des webhooks n'est pas instantanée, alors ajoutez un court délai d'attente ou un réessai par sondage avant la requête pour que votre test ne précède pas Stripe. Quelques réessais sur quelques secondes suffisent généralement. Si vous débutez avec les assertions sur les endpoints asynchrones, commencez par le guide général comment tester les webhooks avant d'ajouter les spécificités de Stripe.
La fonctionnalité Webhook native est-elle utile ici ? Pas pour capturer les événements Stripe. Cette fonctionnalité définit et documente vos propres webhooks sortants, où votre système appelle une URL externe. C'est un outil de documentation et de conception, distinct du modèle "capturer puis interroger" entrant que cet article utilise. Gardez les deux bien distincts.
En résumé
Vous ne pouvez pas pointer Stripe vers Apidog et intercepter les événements en direct, et faire semblant du contraire mène à un après-midi frustrant. La voie prise en charge est plus propre qu'il n'y paraît : capturez le webhook dans votre propre endpoint, enregistrez-le dans une table Stripe event logs, puis laissez le Post-Request Processor d'Apidog interroger cet enregistrement et affirmer que l'événement a été traité. Intégrez le scénario enregistré dans apidog run et votre pipeline prouvera, à chaque fusion, qu'un événement de paiement réel fait passer votre commande au statut payé. Essayez-le gratuitement, sans carte de crédit requise, et mettez une véritable assertion derrière le webhook qui compte le plus.
