Skip to content
Learni
Voir tous les tutoriels
Automatisation

Comment automatiser la facturation avec Stripe en 2026

Read in English

Introduction

L'automatisation de la facturation est essentielle pour tout SaaS ou service en ligne en 2026. Manuellement gérer les abonnements, générer des PDF et envoyer des rappels expose à des erreurs coûteuses et freine la scalabilité. Avec Stripe Billing, vous centralisez les paiements récurrents, tandis que des webhooks déclenchent des actions automatisées comme la création de factures PDF et l'envoi d'emails.

Ce tutoriel intermédiaire vous guide pas à pas pour implémenter un système complet en Node.js/TypeScript : réception de webhooks Stripe (ex. invoice.paid), génération de PDF personnalisés avec pdfkit, et envoi via nodemailer. Imaginez : un client paie, et en 5 secondes, il reçoit sa facture par email.

Pourquoi c'est crucial ? Réduisez le churn de 20-30% grâce à une expérience fluide, économisez 10h/semaine, et respectez RGPD/DSGVO avec des logs traçables. Prêt à transformer votre billing en machine autonome ? (128 mots)

Prérequis

  • Node.js 20+ installé
  • Compte Stripe (test mode activé, API keys récupérées)
  • Connaissances de base en TypeScript et Express
  • Serveur SMTP (Gmail App Password ou SendGrid)
  • Outils : npm/yarn, ngrok pour tester webhooks localement

Initialisation du projet

terminal
mkdir billing-automation && cd billing-automation
npm init -y
npm install express stripe pdfkit nodemailer @types/node @types/express dotenv stripe-node-webhook
npm install -D typescript ts-node @types/pdfkit @types/nodemailer
npx tsc --init --target es2022 --module commonjs --outDir ./dist --rootDir ./src --strict

Ce script crée un projet Node.js, installe les dépendances essentielles (Stripe SDK, pdfkit pour PDF, nodemailer pour emails) et configure TypeScript. Les types évitent les erreurs runtime. Exécutez-le pour un setup prêt en 1 minute ; stripe-node-webhook simplifie la validation des signatures.

Configuration des variables d'environnement

Créez un fichier .env à la racine :

``plaintext
STRIPE_SECRET_KEY=sk_test_votre_cle_secrete
STRIPE_WEBHOOK_SECRET=whsec_votre_secret_webhook
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=votre.email@gmail.com
SMTP_PASS=votre_app_password
`

Analogie : Comme un coffre-fort, ces vars protègent vos clés API. Jamais en dur dans le code ! Ajoutez .env à .gitignore. Dans Stripe Dashboard > Développeurs > Webhooks, créez un endpoint https://votre-domaine.com/webhook et sélectionnez invoice.paid, invoice.payment_failed`.

Structure du serveur principal

src/server.ts
import express from 'express';
import dotenv from 'dotenv';
import { Stripe } from 'stripe-node-webhook';

dotenv.config();

const app = express();
app.use(express.raw({ type: 'application/json' }));
app.use(express.json());

const stripe = new Stripe({
  webhookSecret: process.env.STRIPE_WEBHOOK_SECRET!,
  apiKey: process.env.STRIPE_SECRET_KEY!
});

const PORT = 3000;

app.listen(PORT, () => {
  console.log(`Serveur billing sur port ${PORT}`);
});

export { app, stripe };

Ce serveur Express base gère les body parsers pour webhooks (raw JSON requis par Stripe) et initialise le validateur webhook. Il écoute sur 3000 pour tests locaux. Piège : Oublier express.raw() casse la validation signature. Lancez avec npx ts-node src/server.ts.

Endpoint webhook avec validation

src/webhook.ts
import { app, stripe } from './server';
import { generateInvoicePDF, sendInvoiceEmail } from './invoice';

app.post('/webhook', async (req, res) => {
  try {
    const event = await stripe.parseWebhookRequest(req);
    if (event.type === 'invoice.paid') {
      const invoice = event.data.object as any;
      await generateInvoicePDF(invoice);
      await sendInvoiceEmail(invoice.customer_email, invoice.hosted_invoice_url);
    } else if (event.type === 'invoice.payment_failed') {
      console.log('Paiement échoué:', event.data.object);
    }
    res.status(200).json({ received: true });
  } catch (err) {
    console.error('Webhook error:', err);
    res.status(400).send(`Webhook Error: ${err}`);
  }
});

Cet endpoint valide automatiquement la signature Stripe via stripe-node-webhook, traite invoice.paid en générant PDF/email. Pour payment_failed, loggez pour relances. Sécurité : Toujours répondre 200 sinon Stripe retry infiniment. Intégrez-le après server.ts.

Génération de facture PDF personnalisée

Les PDF doivent être pro : logo, détails ligne, TVA calculée. Utilisez pdfkit pour du SVG-like. Stockez-les sur /invoices/{id}.pdf ou S3. Astuce : Testez avec ngrok (ngrok http 3000) pour exposer localement à Stripe.

Fonction génération PDF

src/invoice.ts
import PDFDocument from 'pdfkit';
import fs from 'fs';

export async function generateInvoicePDF(invoice: any): Promise<string> {
  return new Promise((resolve, reject) => {
    const doc = new PDFDocument();
    const filename = `./invoices/${invoice.id}.pdf`;
    doc.pipe(fs.createWriteStream(filename));

    doc.fontSize(25).text('Facture', 50, 50);
    doc.fontSize(12).text(`ID: ${invoice.id}`, 50, 100);
    doc.text(`Montant: ${invoice.amount_paid / 100}€`, 50, 120);
    doc.text(`Client: ${invoice.customer_email}`, 50, 140);
    doc.text(`Date: ${new Date(invoice.created * 1000).toLocaleDateString('fr-FR')}`, 50, 160);

    doc.end();
    doc.on('end', () => resolve(filename));
    doc.on('error', reject);
  });
}

Cette fonction crée un PDF basique mais extensible (ajoutez logo via doc.image()). Promesse pour async. Piège : fs synchrone bloque ; utilisez async. Créez dossier invoices/ avant. Scalable vers AWS S3 avec multer-s3.

Fonction envoi email avec pièce jointe

src/invoice.ts
import nodemailer from 'nodemailer';

export async function sendInvoiceEmail(email: string, invoiceUrl: string): Promise<void> {
  const transporter = nodemailer.createTransporter({
    host: process.env.SMTP_HOST,
    port: Number(process.env.SMTP_PORT),
    secure: false,
    auth: {
      user: process.env.SMTP_USER,
      pass: process.env.SMTP_PASS
    }
  });

  // Attachez PDF généré
  await transporter.sendMail({
    from: process.env.SMTP_USER,
    to: email,
    subject: 'Votre facture est disponible',
    html: `<p>Facture attachée. <a href="${invoiceUrl}">Voir en ligne</a></p>`,
    attachments: [{ path: `./invoices/${invoiceUrl.split('/').pop()!}.pdf` }]
  });
}

Nodemailer envoie HTML + PJ PDF. Auth Gmail : Activez 2FA + App Password. Piège : Ports TLS (587) vs SSL (465). Logs transporter.sendMail pour debug. Pour prod, migrez vers SendGrid/Resend pour deliverability >99%.

Test et mise en production

  • Local : npm run dev, ngrok, test webhook Stripe CLI (stripe listen --forward-to localhost:3000/webhook).
  • Prod : Vercel/Render, set env vars, HTTPS obligatoire.
  • Vérifiez logs Stripe Dashboard pour retries.
Exemple flux : Abonnement → Paiement → Webhook → PDF → Email (2s total).

Bonnes pratiques

  • Idempotence : Vérifiez invoice.id en DB pour éviter doublons (utilisez Prisma/PlanetScale).
  • Sécurité : Validez toujours signatures ; rate-limit /webhook avec express-rate-limit.
  • Scalabilité : Queue (BullMQ/Redis) pour PDF/email async ; monitorez avec Sentry.
  • RGPD : Stockez PDF <90 jours, logs anonymisés.
  • Tests : Stripe test clocks pour simuler temps (ex. fin période).

Erreurs courantes à éviter

  • Signature invalide : Oubli express.raw() ou mauvais secret → 400 errors infinis.
  • Emails en spam : Pas de DKIM/SPF → Utilisez transactional email provider.
  • PDF corrompu : Erreur async fs → Await toutes Promises.
  • Pas de retry : Ignorez payment_failed → Implémentez relances auto via Stripe.

Pour aller plus loin

Découvrez nos formations Learni sur Node.js et Stripe pour masteriser le dev full-stack scalable.
Comment automatiser facturation Stripe 2026 | Learni