MÉTRIQUES DE CHURNLEMON SQUEEZY

Suivre le churn avec les webhooks Lemon Squeezy

Quels webhooks Lemon Squeezy marquent une annulation, une expiration, un paiement échoué ou récupéré, et comment en faire un journal de churn fiable.

Publié le 6 min de lecture

Si vous vendez des abonnements via Lemon Squeezy, tous les signaux de churn dont vous avez besoin passent par ses webhooks : annulations, expirations, renouvellements échoués, récupérations, pauses. Le plus difficile n’est pas de les recevoir. C’est de décider quel événement veut dire quoi, et de les enregistrer de façon à ce que vos chiffres de churn tiennent toujours debout six mois plus tard.

Ce guide fait correspondre les événements d’abonnement de Lemon Squeezy aux notions de churn, montre comment les stocker, et liste les détails de livraison qui cassent les handlers naïfs. Il s’en tient à la documentation de Lemon Squeezy : les types d’événements webhook, la page des requêtes webhook, la signature des requêtes, le guide de synchronisation par webhooks et la référence de l’objet Subscription (tous consultés en novembre 2026).

Les événements d’abonnement

La page des types d’événements de Lemon Squeezy liste ces événements d’abonnement :

Événement Ce qui le déclenche selon Lemon Squeezy Signification pour le churn
subscription_created Un nouvel abonnement Client nouveau (ou de retour)
subscription_updated Tout changement après le paiement initial À utiliser pour synchroniser le statut
subscription_cancelled Annulé par le client ou le propriétaire de la boutique ; entre en période de grâce jusqu’à la prochaine date de facturation Churn programmé, pas encore arrivé
subscription_resumed Réactivé après une annulation Churn programmé annulé
subscription_expired Terminé après une annulation, ou une fois les relances terminées pour les abonnements past_due Churn arrivé
subscription_paused Encaissement mis en pause Pas du churn ; à suivre à part
subscription_unpaused Encaissement repris Fin de pause
subscription_payment_success Un paiement réussi Revenu
subscription_payment_failed Un paiement de renouvellement a échoué Risque de churn involontaire
subscription_payment_recovered Un paiement réussi après un échec Risque levé
subscription_payment_refunded Un paiement remboursé Ajustement de revenu

Deux d’entre eux méritent qu’on s’y attarde.

Annulé ne veut pas dire parti

subscription_cancelled se déclenche quand le client clique sur annuler, mais l’abonnement continue jusqu’à ends_at. Pendant cette période de grâce, il peut être réactivé, ce qui envoie subscription_resumed. Si vous comptez le churn sur subscription_cancelled, chaque abonnement réactivé devient un faux churn, et votre date de churn est décalée de jusqu’à une période de facturation entière.

Comptez le churn sur subscription_expired. Gardez subscription_cancelled comme un indicateur avancé à part : « annulations programmées ce mois-ci ».

Un événement, deux types de churn

subscription_expired se déclenche pour deux raisons très différentes : un client qui a annulé et atteint ends_at (churn volontaire), et un abonnement passé par les relances après des paiements échoués sans être récupéré (churn involontaire). Le nom de l’événement ne vous dit pas lequel.

Pour les séparer, regardez ce qui est arrivé avant. Si votre journal contient un subscription_cancelled pour cet abonnement sans subscription_resumed ensuite, c’est volontaire. S’il contient des événements subscription_payment_failed sans récupération, c’est involontaire. Vous pouvez aussi lire l’état de l’abonnement à la réception de l’événement : la référence de l’objet Subscription montre un booléen cancelled à côté de status.

Le churn volontaire et le churn involontaire demandent des remèdes différents : cette séparation est la chose la plus utile que votre journal puisse vous donner.

À quoi ressemblent les requêtes

D’après la page des requêtes webhook :

  • Chaque requête est un POST avec un corps JSON:API : la ressource liée à l’événement (un abonnement pour la plupart des événements d’abonnement, une subscription invoice pour les événements de paiement).
  • L’en-tête X-Event-Name porte le nom de l’événement.
  • L’en-tête X-Signature porte la signature.
  • Votre endpoint doit renvoyer 200. Tout autre statut est retenté jusqu’à trois fois de plus avec un délai exponentiel (la doc donne 5, 25 et 125 secondes en exemple), après quoi la requête est considérée comme échouée.

La page des réglages webhooks de votre dashboard journalise les livraisons récentes avec leur contenu et permet de les renvoyer. C’est votre filet de sécurité si votre endpoint était en panne.

Vérifier la signature

La signature des requêtes explique le principe : vous définissez un secret de signature à la création du webhook (6 à 40 caractères), et Lemon Squeezy calcule avec lui un condensé hexadécimal HMAC-SHA256 du corps de la requête. Recalculez le condensé sur le corps brut, pas sur du JSON resérialisé, et comparez avec une fonction à temps constant. Rejetez tout ce qui ne correspond pas.

Les événements de paiement portent des factures

Les événements subscription_payment_* portent un objet subscription invoice, pas l’abonnement. Il fait référence à l’abonnement : stockez cet identifiant et, si vous avez besoin du statut, récupérez l’abonnement.

Construire un journal de churn pas à pas

L’objectif est une table en ajout seul de ce qui est arrivé à chaque abonnement, à partir de laquelle chaque indicateur de churn peut être recalculé.

  1. Créez un seul endpoint pour tous les événements d’abonnement. Abonnez-le aux événements du tableau ci-dessus. Le guide de synchronisation de Lemon Squeezy indique que subscription_updated couvre chaque changement : vous pouvez donc vous abonner à lui seul si vous ne voulez que l’état. Pour le suivi du churn, les événements spécifiques sont plus faciles à interpréter : prenez les deux.
  2. Vérifiez, puis stockez le contenu brut. Écrivez le nom de l’événement, l’identifiant de l’abonnement, l’identifiant du client, l’horodatage et le JSON brut avant de faire quoi que ce soit d’autre.
  3. Dédoublonnez. Les nouvelles tentatives et les renvois manuels font qu’un même événement peut arriver deux fois. Les docs que nous avons utilisées ne décrivent pas d’identifiant d’événement unique dans la requête : construisez votre propre clé à partir du nom de l’événement, de l’identifiant de la ressource et du updated_at de la ressource, et ignorez les répétitions.
  4. Répondez vite. Renvoyez 200 dès que l’événement est stocké, et traitez-le dans une tâche en arrière-plan. Un handler lent qui dépasse le délai déclenche des nouvelles tentatives.
  5. Dérivez, n’écrasez pas. Gardez le journal immuable. Calculez le « statut actuel » et les comptes de churn à partir de lui : un bug dans votre logique peut alors être corrigé en rejouant le journal.
  6. Rapprochez de temps en temps. Une fois par semaine, listez les abonnements via l’API et comparez leurs statuts à ce que dit votre journal. Tout écart signale un événement manqué.

Les indicateurs que vous pouvez calculer

Avec ce journal, ceux-ci sont simples :

  • Taux de churn clients sur un mois : abonnements expirés pendant le mois, divisés par les abonnements actifs au début du mois.
  • Part volontaire et involontaire : expirations réparties selon la règle ci-dessus.
  • Annulations programmées : événements subscription_cancelled du mois, un indicateur avancé du churn du mois suivant.
  • Sauvetages pendant la période de grâce : abonnements annulés suivis d’un subscription_resumed.
  • Taux de récupération des paiements : abonnements avec un subscription_payment_recovered divisés par les abonnements avec un subscription_payment_failed sur la même période.
  • Part en pause : abonnements actuellement paused. Présentez-les à part ; ce ne sont ni des payeurs actifs ni des clients partis.

Définissez chaque indicateur une fois, par écrit, et gardez la définition stable. Un taux de churn n’est utile que comparé à lui-même dans le temps.

Tester avant de s’y fier

Le mode test de Lemon Squeezy peut simuler des événements webhook pour les abonnements. Faites-y passer chaque cycle de vie : création, annulation, réactivation, nouvelle annulation puis expiration ; un paiement échoué qui est récupéré ; un autre qui ne l’est pas. Vérifiez qu’à chaque étape votre journal et vos indicateurs correspondent à ce que vous attendez.

Le faire avec NoChurn

Lemon Squeezy reste la source de vérité pour les abonnements et les paiements ; NoChurn ne les modifie pas. NoChurn s’abonne à vos webhooks Lemon Squeezy, stocke et dédoublonne les événements, et sépare pour vous le churn volontaire du churn involontaire. Il ajoute un churn score de 0 à 100 par client, les données personnalisées que vous envoyez par API, et les réponses du parcours d’annulation qui expliquent pourquoi les gens partent. Les litiges, que Lemon Squeezy gère en tant que marchand officiel, sont affichés en lecture seule. Voir NoChurn + Lemon Squeezy.

PROMPT

Read https://www.nochurn.sh/llms.txt,
then follow https://www.nochurn.sh/docs/quickstart/
to add NoChurn to this app. Use a test key
(nc_test_…) until I say we go live.

Arrêtez de perdre du revenu.

  • Gratuit jusqu’à $300 de MRR
  • Sans carte bancaire
  • Prêt en 10 minutes
  • Jamais une commission sur ce que nous récupérons