Intégration Stripe : comment connecter paiements et facturation

Intégration Stripe : comment connecter paiements et facturation

Introduction

L'intégration Stripe constitue une étape déterminante pour tout système nécessitant des paiements en ligne et une facturation automatisée. Stripe offre une API RESTful complète, des webhooks temps réel et un tableau de bord robuste pour gérer l'ensemble du cycle de vie transactionnel.

Ce guide couvre la connexion de Stripe à un système existant, la gestion des paiements, la configuration des webhooks et l'automatisation de la facturation — de l'authentification initiale jusqu'aux erreurs courantes à éviter.

Prérequis à l'intégration Stripe

Avant de débuter, plusieurs éléments doivent être en place :

  • Un compte Stripe (mode test activé par défaut)
  • Une clé API disponible dans le tableau de bord (Dashboard → Developers → API keys)
  • Un serveur backend capable d'effectuer des requêtes HTTPS vers l'API Stripe
  • Un certificat SSL/TLS valide (Stripe refuse les connexions non sécurisées)

Stripe fournit deux paires de clés :

Type Usage
sk_test_… Clé secrète de test (jamais côté client)
pk_test_… Clé publique de test (côté frontend)
sk_live_… Clé secrète de production
pk_live_… Clé publique de production

Les clés secrètes ne doivent jamais être exposées dans le code frontend. Elles transitent exclusivement par le serveur backend.

Authentification et configuration initiale

L'authentification Stripe repose sur le Bearer Token. Chaque requête vers l'API inclut la clé secrète dans l'en-tête Authorization.

curl https://api.stripe.com/v1/charges \
  -u sk_test_VOTRE_CLE: \
  -d amount=2000 \
  -d currency=eur \
  -d description="Paiement commande #1234" \
  -d source=tok_visa

En Node.js, le SDK officiel simplifie l'initialisation :

const Stripe = require('stripe');
const stripe = Stripe('sk_test_VOTRE_CLE');

// Vérification de la connexion
const balance = await stripe.balance.retrieve();
console.log(balance.available);

En Python :

import stripe
stripe.api_key = "sk_test_VOTRE_CLE"

balance = stripe.Balance.retrieve()
print(balance['available'])

Créer un paiement avec Stripe API

Payment Intents : l'approche recommandée

Stripe recommande l'utilisation de Payment Intents pour tous les nouveaux projets. Ce flux gère nativement l'authentification forte (SCA), les paiements différés et la gestion des erreurs.

Le flux se déroule en trois étapes :

1. Création du Payment Intent côté serveur :

const paymentIntent = await stripe.paymentIntents.create({
  amount: 5000, // en centimes
  currency: 'eur',
  metadata: {
    order_id: 'CMD-2026-0042',
    customer_reference: 'REF-ABC'
  }
});

2. Confirmation côté client avec Stripe.js :

const { error } = await stripe.confirmCardPayment(clientSecret, {
  payment_method: {
    card: cardElement,
    billing_details: {
      name: 'Jean Dupont'
    }
  }
});

3. Vérification côté serveur :

const intent = await stripe.paymentIntents.retrieve(paymentIntent.id);

if (intent.status === 'succeeded') {
  // Mettre à jour la commande en base de données
  await updateOrderStatus(orderId, 'paid');
}

Gérer les statuts de paiement

Un Payment Intent traverse plusieurs états :

Statut Signification
requires_payment_method Aucune méthode de paiement fournie
requires_confirmation Prêt à être confirmé
requires_action Authentification supplémentaire requise (SCA)
processing Paiement en cours de traitement
succeeded Paiement validé
requires_capture Autorisé mais non capturé
canceled Paiement annulé

Chaque transition de statut déclenche un événement webhook — un point crucial pour maintenir la synchronisation entre Stripe et le système interne.

Configurer les Stripe Webhooks

Les webhooks constituent le mécanisme central pour recevoir les événements de Stripe en temps réel. Sans eux, le système doit interroger l'API périodiquement (polling), ce qui est peu fiable et coûteux en ressources.

Enregistrement d'un endpoint webhook

Depuis le Dashboard Stripe (Developers → Webhooks) ou via l'API :

const webhook = await stripe.webhookEndpoints.create({
  url: 'https://votre-domaine.com/api/stripe/webhook',
  enabled_events: [
    'payment_intent.succeeded',
    'payment_intent.payment_failed',
    'invoice.paid',
    'invoice.payment_failed',
    'customer.subscription.created',
    'customer.subscription.deleted'
  ]
});

Vérification de la signature webhook

Chaque événement envoyé par Stripe inclut une signature dans l'en-tête Stripe-Signature. La vérification empêche les attaques par falsification :

const sig = request.headers['stripe-signature'];
const endpointSecret = 'whsec_VOTRE_SECRET';

let event;

try {
  event = stripe.webhooks.constructEvent(
    request.rawBody,
    sig,
    endpointSecret
  );
} catch (err) {
  response.status(400).send(`Webhook Error: ${err.message}`);
  return;
}

// Traitement de l'événement
switch (event.type) {
  case 'payment_intent.succeeded':
    const paymentIntent = event.data.object;
    await fulfillOrder(paymentIntent);
    break;
  case 'invoice.paid':
    const invoice = event.data.object;
    await generateInvoicePDF(invoice);
    break;
}

Événements essentiels à écouter

Pour un système de facturation complet, ces événements sont indispensables :

  • payment_intent.succeeded — Confirmer le paiement et déclencher la livraison
  • payment_intent.payment_failed — Notifier et proposer un nouveau moyen de paiement
  • invoice.paid — Marquer la facture comme payée, archiver
  • invoice.payment_failed — Tenter une relance automatique
  • customer.subscription.updated — Synchroniser le plan d'abonnement
  • customer.subscription.deleted — Révoquer les accès

Connecter Stripe à un système de facturation

Création de factures programmées

Stripe Billing automatise entièrement le cycle de facturation récurrente. La configuration passe par la création de produits et de prix :

// Création d'un produit
const product = await stripe.products.create({
  name: 'Plan Professionnel',
  description: 'Accès complet à la plateforme'
});

// Création d'un prix récurrent
const price = await stripe.prices.create({
  product: product.id,
  unit_amount: 4900,
  currency: 'eur',
  recurring: {
    interval: 'month'
  }
});

Abonnements clients

Un client Stripe regroupe les informations de paiement réutilisables :

const customer = await stripe.customers.create({
  email: 'client@exemple.com',
  name: 'Entreprise ABC',
  metadata: {
    internal_id: 'CLI-0042'
  }
});

// Création de l'abonnement
const subscription = await stripe.subscriptions.create({
  customer: customer.id,
  items: [{ price: price.id }],
  payment_behavior: 'default_incomplete',
  expand: ['latest_invoice.payment_intent']
});

Gestion des factures

Chaque abonnement génère automatiquement des factures. La récupération se fait via l'API :

const invoices = await stripe.invoices.list({
  customer: customer.id,
  limit: 12,
  status: 'paid'
});

// Génération du PDF de facture
const invoicePdf = await stripe.invoices.retrievePDF(invoice.id);

Stripe permet aussi la facturation ponctuelle (one-off) :

const invoiceItem = await stripe.invoiceItems.create({
  customer: customer.id,
  amount: 15000,
  currency: 'eur',
  description: 'Services de consulting - Mars 2026'
});

const invoice = await stripe.invoices.create({
  customer: customer.id,
  auto_advance: true // génère et envoie automatiquement
});

await stripe.invoices.finalizeInvoice(invoice.id);
await stripe.invoices.sendInvoice(invoice.id);

Automatisation et bonnes pratiques

Idempotency Keys

Chaque mutation de l'API Stripe devrait inclure une clé d'idempotence. Cette clé empêche la double exécution en cas de timeout ou de retry réseau :

const paymentIntent = await stripe.paymentIntents.create({
  amount: 5000,
  currency: 'eur',
}, {
  idempotencyKey: `order-${orderId}-${Date.now()}`
});

Retry logique avec exponential backoff

Les appels API peuvent échouer temporairement (rate limit, timeout). Une stratégie de retry avec backoff exponentiel est recommandée :

async function stripeCall(fn, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (err) {
      if (err.statusCode === 429 || err.statusCode >= 500) {
        const delay = Math.pow(2, i) * 1000 + Math.random() * 1000;
        await new Promise(r => setTimeout(r, delay));
        continue;
      }
      throw err;
    }
  }
  throw new Error('Max retries exceeded');
}

Journalisation structurée

Chaque interaction avec Stripe devrait être journalisée avec les identifiants pertinents :

logger.info('Payment intent created', {
  payment_intent_id: paymentIntent.id,
  amount: paymentIntent.amount,
  currency: paymentIntent.currency,
  order_id: orderId,
  timestamp: new Date().toISOString()
});

Gestion des échecs de paiement

Pour les abonnements, Stripe propose un mécanisme de relance automatique (Smart Retries) configurable :

await stripe.subscriptions.update(subscription.id, {
  days_until_due: 14,
  collection_method: 'send_invoice',
  payment_settings: {
    payment_method_types: ['card', 'sepa_debit']
  }
});

Un webhook invoice.payment_failed déclenche la logique métier : notification email, suspension temporaire des accès, relance manuelle.

Tests et mode sandbox

Stripe fournit un ensemble de numéros de carte de test :

Carte Résultat
4242 4242 4242 4242 Paiement réussi
4000 0000 0000 0002 Paiement refusé
4000 0025 0000 3155 Authentification 3D Secure requise
4000 0000 0000 9995 Perte de carte

L'utilisation du CLI Stripe permet de simuler des webhooks en local :

stripe listen --forward-to localhost:3000/api/stripe/webhook
stripe trigger payment_intent.succeeded

Migration de test à production

Le passage en production nécessite plusieurs vérifications :

  1. Remplacer les clés de test par les clés live (sk_live_… / pk_live_…)
  2. Activer le endpoint webhook en production avec un certificat SSL valide
  3. Configurer les méthodes de paiement activées pour chaque devise
  4. Activer Radar (anti-fraude) et définir les règles métier
  5. Configurer les notifications email (reçus, relances)
  6. Vérifier la conformité RGPD et PCI-DSS

Stripe gère la majeure partie de la conformité PCI-DSS (niveau 1), mais la gestion des données sensibles côté serveur reste de la responsabilité de l'intégrateur.

FAQ

Quels langages de programmation sont supportés par Stripe ?

Stripe propose des SDK officiels pour Ruby, Python, PHP, Java, Node.js, Go, .NET et Java. Une API REST est disponible pour tout autre langage. La documentation inclut des exemples pour chaque SDK.

Comment gérer les remboursements via l'API ?

Les remboursements s'effectuent via l'endpoint dédié :

const refund = await stripe.refunds.create({
  payment_intent: 'pi_3AbcDefGhiJkl',
  amount: 2500 // remboursement partiel (en centimes)
});

Un remboursement total se fait en omettant le paramètre amount. Le webhook charge.refunded notifie le système.

Stripe supporte-t-il les paiements SEPA ?

Oui. Stripe supporte SEPA Direct Debit pour les prélèvements en euros dans les 36 pays de la zone SEPA. La configuration nécessite l'activation dans le Dashboard et l'utilisation du type de paiement sepa_debit. Le cycle de confirmation est plus long que pour les cartes (2-4 jours ouvrés).

Que faire en cas de webhook manqué ?

Stripe propose un mécanisme de retry automatique pendant 72 heures avec un backoff exponentiel. En cas d'échec définitif, l'événement apparaît dans la section "Failed webhooks" du Dashboard. Une API permet de relister les événements récents :

const events = await stripe.events.list({
  type: 'payment_intent.succeeded',
  created: { gte: Math.floor(Date.now() / 1000) - 86400 }
});

Comment sécuriser l'intégration Stripe ?

Les bonnes pratiques incluent : validation côté serveur de tous les montants, utilisation systématique des clés d'idempotence, vérification des signatures webhook, activation de Radar pour la détection de fraude, restriction des méthodes de paiement aux seules devises supportées, et audit régulier des logs Stripe.

blog.share

8 min de lecture