Intégrer Stripe dans un SaaS français : TVA, factures, webhooks
Guide complet pour intégrer Stripe dans un SaaS B2B français — gestion de la TVA, factures conformes, webhooks sécurisés et abonnements.
Stripe en France — ce qui change
Intégrer Stripe dans un SaaS français n'est pas juste "copier-coller la doc US". Il y a la TVA à 20%, les factures conformes à générer, et des règles spécifiques pour les abonnements B2B.
Étape 1 — Configuration Stripe
// src/lib/stripe.ts
import Stripe from "stripe";
export const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
apiVersion: "2025-02-24.acacia",
typescript: true,
});Produits et prix
Créez vos plans dans le dashboard Stripe avec les bons taux de TVA :
// Exemple de création programmatique
const product = await stripe.products.create({
name: "HeartCo Pro",
tax_code: "txcd_10103001", // SaaS - Software as a Service
});
const price = await stripe.prices.create({
product: product.id,
unit_amount: 3400, // 34€ HT
currency: "eur",
recurring: { interval: "month" },
tax_behavior: "exclusive", // TVA ajoutée en plus
});Étape 2 — Checkout Session
// src/server/api/routers/billing.ts
export const billingRouter = createTRPCRouter({
createCheckout: staffProcedure
.input(z.object({ priceId: z.string() }))
.mutation(async ({ ctx, input }) => {
const session = await stripe.checkout.sessions.create({
customer_email: ctx.session.user.email,
mode: "subscription",
line_items: [{ price: input.priceId, quantity: 1 }],
automatic_tax: { enabled: true },
tax_id_collection: { enabled: true },
success_url: `${env.NEXT_PUBLIC_APP_URL}/dashboard/billing?success=true`,
cancel_url: `${env.NEXT_PUBLIC_APP_URL}/dashboard/billing`,
metadata: {
organizationId: ctx.session.user.organizationId,
},
});
return { url: session.url };
}),
});Points clés pour la France
automatic_tax: { enabled: true }— Stripe calcule la TVA automatiquement selon le pays du clienttax_id_collection— Permet au client de saisir son numéro de TVA intracommunautairemetadata— Toujours inclure l'organizationIdpour le webhook
Étape 3 — Webhooks sécurisés
Le webhook est le point critique. C'est lui qui met à jour votre base de données quand un paiement est confirmé.
// src/app/api/webhooks/stripe/route.ts
import { headers } from "next/headers";
import crypto from "crypto";
export async function POST(req: Request) {
const body = await req.text();
const headersList = await headers();
const signature = headersList.get("stripe-signature")!;
// Vérification HMAC — OBLIGATOIRE
let event: Stripe.Event;
try {
event = stripe.webhooks.constructEvent(
body,
signature,
process.env.STRIPE_WEBHOOK_SECRET!,
);
} catch {
return new Response("Invalid signature", { status: 400 });
}
switch (event.type) {
case "checkout.session.completed": {
const session = event.data.object;
const orgId = session.metadata?.organizationId;
if (!orgId) break;
await db.subscription.update({
where: { organizationId: orgId },
data: {
plan: "PRO",
stripeSubscriptionId: session.subscription as string,
status: "ACTIVE",
},
});
break;
}
case "customer.subscription.deleted": {
// Downgrade vers FREE
const sub = event.data.object;
await db.subscription.updateMany({
where: { stripeSubscriptionId: sub.id },
data: { plan: "FREE", status: "CANCELED" },
});
break;
}
}
return new Response("OK", { status: 200 });
}Règle de sécurité critique
Ne jamais comparer les signatures avec === :
// ❌ VULNÉRABLE — timing attack
if (computedSignature === receivedSignature) { ... }
// ✅ SÉCURISÉ — comparaison en temps constant
crypto.timingSafeEqual(
Buffer.from(computedSignature),
Buffer.from(receivedSignature),
);Stripe SDK le fait pour vous via constructEvent, mais si vous vérifiez manuellement, utilisez toujours timingSafeEqual.
Étape 4 — Factures conformes
Pour un SaaS B2B français, vos factures doivent inclure :
- Numéro séquentiel (FACT-2026-001)
- TVA ventilée (HT + TVA + TTC)
- Mentions légales (SIRET, numéro TVA)
- Date d'émission et de paiement
Stripe génère des factures automatiquement pour les abonnements. Activez Stripe Invoicing et configurez vos informations légales dans le dashboard.
Checklist Stripe France
-
automatic_taxactivé sur toutes les Checkout Sessions -
tax_id_collectionactivé pour les clients B2B - Webhook vérifié par signature HMAC
- Informations légales dans Stripe Dashboard (SIRET, TVA)
- Gestion du downgrade à l'expiration de l'abonnement
- Emails de confirmation configurés (Stripe ou custom)
- Mode test validé avant passage en production
Le paiement est la partie la plus sensible de votre SaaS. Prenez le temps de bien le configurer — vos clients (et votre comptable) vous remercieront.