Configurez un endpoint webhook Stripe, vérifiez Stripe-Signature avec le corps brut, testez avec stripe listen et stripe trigger, et traitez chaque commande Checkout une seule fois.
Un webhook Stripe est un endpoint HTTPS sur votre serveur auquel Stripe envoie en POST le JSON d'un événement, comme checkout.session.completed après un paiement. Votre handler doit vérifier l'en-tête Stripe-Signature sur le corps brut intact à l'aide du secret whsec_ de l'endpoint, renvoyer rapidement un 2xx et supporter que le même événement arrive plusieurs fois.
L'essentiel des webhooks Stripe (vérifié dans la documentation Stripe, octobre 2026)
La plupart des intégrations Stripe défaillantes échouent à l'un de ces trois endroits : le framework a parsé le corps avant la vérification, le handler a fait un travail lent et a expiré, ou un événement renvoyé a traité une commande deux fois. Ce guide présente un handler qui évite les trois, avec un vérificateur ci-dessous qui contrôle un en-tête Stripe-Signature dans votre navigateur pour que vous voyiez exactement ce que calcule la bibliothèque.
Presque toujours parce que le corps a été modifié avant la vérification, par exemple par express.json() ou un body parser qui réencode le JSON. Montez express.raw({ type: "application/json" }) uniquement sur la route du webhook, ou lisez request.text() dans un route handler Next.js. Un mauvais secret provoque le même message.
checkout.session.completed pour les paiements par carte, plus checkout.session.async_payment_succeeded pour les moyens différés comme les prélèvements bancaires. Stripe conseille aussi de gérer checkout.session.async_payment_failed afin de pouvoir prévenir le client. Vérifiez le payment_status de la session avant de traiter la commande.
Non. La documentation de Stripe indique elle-même qu'un client peut payer et fermer l'onglet avant que votre page de succès ne se charge. Utilisez la page de succès pour une confirmation rapide si vous le souhaitez, mais le webhook doit aussi déclencher le traitement, et les deux chemins doivent pouvoir s'exécuter deux fois sans risque.
Stripe ne garantit pas l'ordre. invoice.paid peut arriver avant customer.subscription.created. Suivez les identifiants d'événements pour repérer les doublons et récupérez l'objet associé via l'API quand vous avez besoin de son état le plus récent.
Cliquez sur Resend sur l'événement dans le Dashboard (possible jusqu'à 15 jours après sa création) ou lancez stripe events resend <event_id> --webhook-endpoint=<endpoint_id> avec la CLI (jusqu'à 30 jours). Les nouvelles tentatives automatiques continuent dans tous les cas.
express.raw est monté sur cette route uniquement, le corps arrive donc à constructEvent sous forme d'octets d'origine.
request.text() donne le corps non parsé. Une exception dans constructEvent signifie que la signature ou le secret est incorrect.
listen affiche un secret whsec_ pour cette session. Placez-le dans votre env local, puis déclenchez des événements dans un second terminal.
Types d'événements Stripe courants et quoi faire
Collez un en-tête Stripe-Signature, le corps brut et votre secret whsec_ pour voir la même vérification que celle des bibliothèques. Tout s'exécute dans votre navigateur avec Web Crypto et rien n'est envoyé. Utilisez un secret du mode test, jamais un secret live.
En-tête Stripe-Signature
Corps brut de la requête
Secret de l'endpoint (whsec_...)
Tolérance en secondes
Signer ce corps maintenant
Vérifier
Résultat
L'en-tête ne contient pas de timestamp t=.
L'en-tête ne contient pas de signature v1=.
v1 attendu : {v}
La signature correspond.
La signature ne correspond pas : le corps a été modifié ou le secret est incorrect.
Le timestamp date de {n} secondes, dans la tolérance.
Le timestamp date de {n} secondes, hors de la tolérance : une bibliothèque le rejetterait.
Commencer gratuitement · Sans carte bancaire