SaaS · facturation et CRM
Synchronisation Stripe Billing vers le CRM : abonnements, paiements et MRR en affaires, sans événement perdu ni doublon
Une application de marketplace qui reproduit dans un CRM les clients, abonnements et paiements Stripe en contacts et en affaires, avec un registre de webhooks signés, une row-level security par tenant et un rapprochement quotidien.
- Secteur
- SaaS · facturation et CRM
- Technologies
- TypeScript · NestJS · PostgreSQL 16 + Drizzle
Le défi
Des entreprises qui facturent via Stripe voulaient que leur CRM indique qui paie, avec quelle offre et pour quelle valeur mensuelle, sans mise à jour manuelle. Les webhooks Stripe n'arrivent pas dans l'ordre, peuvent arriver deux fois et transportent un instantané parfois déjà dépassé : une synchronisation qui leur fait confiance écrit de mauvaises étapes et crée des affaires en double. L'application sert en outre de nombreuses entreprises à la fois et détient leurs clés Stripe : l'isolation et la gestion des secrets faisaient donc partie du cahier des charges dès le premier jour.
La solution
Nous avons développé un backend hébergé qui fait tourner trois processus à partir d'une seule image : API, worker et planificateur. Le point d'entrée vérifie la signature Stripe sur le corps brut de la requête, identifie le tenant uniquement à partir du jeton de l'endpoint et renvoie un 2xx sans exécuter de logique métier. Chaque événement est inscrit dans un registre et placé en file d'attente dans une même transaction, avec une outbox pour ne rien perdre si Redis tombe. Avant toute écriture, le worker récupère l'objet actuel auprès de Stripe et écarte les événements périmés, puis associe les abonnements à des affaires avec étape, MRR, devise et contact. Un rapprochement quotidien rattrape tout ce que les webhooks ont manqué.
Comment tout s'enchaîne
- 01 Vérifier le webhook
- 02 Registre et file
- 03 Lire l'état actuel
- 04 Associer à une affaire
- 05 Écrire dans le CRM
- 06 Rapprochement quotidien
Ce que nous avons livré
- Point d'entrée des webhooks avec vérification de la signature sur le corps brut et identification du tenant par le jeton de l'endpoint
- Registre d'événements avec mise en file transactionnelle et vidage d'une outbox
- Files d'attente avec politique de nouvelles tentatives, disjoncteur (circuit breaker) et verrous par objet
- Correspondance abonnement–affaire avec étape, MRR (signalé quand il est incomplet), devise et contacts
- Recherche d'affaires qui vérifie sa propre correspondance avant d'écrire
- Import initial de l'historique par tranches, avec reprise possible, plus un rapprochement quotidien
- Assistant de configuration en quatre étapes et 11 langues, qui crée lui-même les champs et les étapes de pipeline dans le CRM
- Plusieurs comptes Stripe par utilisateur, tâches de conservation des données et statistiques d'installation
- Environ 590 cas de test automatisés
Fonctionnalités
- Row-level security PostgreSQL sur chaque table métier ; les clés uniques incluent le tenant et le compte Stripe
- Chiffrement par enveloppe (envelope encryption) des secrets stockés
- Les champs et les étapes renseignés à la main dans le CRM ne sont jamais écrasés
- Les erreurs qui ne peuvent pas aboutir en réessayant passent à l'état « action requise » au lieu d'être relancées indéfiniment
- La page de configuration ne charge aucun script tiers, car les utilisateurs y collent une clé Stripe
- Sauvegardes quotidiennes, contrôlées par des restaurations de test
- Journaux structurés sans données personnelles
Intégrations
- API et webhooks Stripe Billing
- API du CRM du client : contacts, affaires, pipelines et champs personnalisés
- Marketplace d'applications du client
Technologies
Résultat
Déployée sur un serveur de staging hébergé et en recette avec un compte Stripe réel. La recette et une revue de sécurité ont relevé des défauts ; ceux qui relèvent de l'application sont corrigés et retestés. La publication sur la marketplace suivra la recette.
Pourquoi interroger Stripe avant chaque écriture ?
Un webhook indique que quelque chose a changé, pas ce qui est vrai maintenant. Deux événements concernant le même abonnement peuvent arriver dans le désordre, et le plus ancien écraserait alors l’état le plus récent. L’application ne lit donc dans le webhook que l’identifiant de l’événement, son type et l’identifiant de l’objet, puis récupère l’objet actuel auprès de Stripe avant d’écrire quoi que ce soit dans le CRM. Grâce au registre, un événement répété reste sans effet, et le rapprochement quotidien comble tout écart laissé par une livraison manquée.
Parlons de votre projet
Présentez-nous votre projet