Webhooks Stripe : signature et idempotence

Advanced Ecosystem 🟡 Mid

Définition

Stripe notifie votre serveur des événements (paiement réussi, abonnement annulé) par requêtes HTTP signées. Trois règles : vérifier la signature (en-tête Stripe-Signature) sur le corps brut, répondre 2xx vite puis traiter en tâche de fond, et rendre le traitement idempotent car un même événement peut arriver plusieurs fois (Stripe réessaie avec délai croissant pendant trois jours en mode live, l'identifiant evt_ restant identique). On stocke les identifiants d'événements traités.

Analogie

Le facteur peut sonner deux fois avec le même recommandé : on vérifie le cachet, on signe l'accusé tout de suite, et on note le numéro pour ne pas ouvrir deux fois le même colis.

Exemple de code

// Express : corps BRUT obligatoire pour vérifier la signature
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'], WEBHOOK_SECRET);
  } catch { return res.status(400).send('Signature invalide'); }

  // Idempotence : INSERT échoue si evt_ déjà vu (clé primaire)
  const fresh = await db.insertIgnore('stripe_events', { id: event.id, type: event.type });
  if (!fresh) return res.sendStatus(200);          // doublon → on ignore

  await queue.add('stripe', event);                // traitement asynchrone
  res.sendStatus(200);                             // répondre vite
});

Cas d'usage

Activer un abonnement, débloquer un téléchargement ou envoyer une facture uniquement quand Stripe confirme le paiement, sans jamais le faire deux fois.

Anti-pattern

Faire confiance au retour de la page de succès Checkout pour livrer : seul le webhook (ou la vérification serveur de la session) fait foi.
#payment#webhooks#backend

Fiche mise à jour le 2026-09-27

← → au clavier pour passer d'une fiche à l'autre