Build This Now
Build This Now
Qu'est-ce que le code Claude ?Installer Claude CodeL'installateur natif de Claude CodeTon premier projet Claude Code
Claude Code v2.1.122 Release NotesClaude Code Dynamic Workflows : comment orchestrer 1 000 sous-agents sur une vraie codebaseBonnes pratiques Claude CodeMeilleures pratiques pour Claude Opus 4.7Claude Code sur un VPSIntégration GitRevue de code avec Claude CodeLes Worktrees avec Claude CodeClaude Code à distanceClaude Code ChannelsChannels, Routines, Teleport, DispatchTâches planifiées avec Claude CodePermissions Claude CodeLe mode auto de Claude CodeAjouter les paiements Stripe avec Claude CodeFeedback LoopsWorkflows TodoGestion des tâches dans Claude CodeTemplates de projetTarification et utilisation des tokens Claude CodeTarifs de Claude Code : ce que tu vas vraiment payerClaude Code Ultra ReviewConstruire une app Next.js avec Claude CodeClaude Code With Supabase: Database, Auth, RLSVercel deepsec with Claude CodeCommerce agentique : comment construire une app que les agents IA peuvent payerClaude Code 1M Context in Practice: When Bigger Isn't BetterClaude Code GitHub Actions Setup Guide (@claude + Cron)Claude Code Headless Mode: The Definitive Guide to claude -pClaude Code Max Plan vs API Cost: Break-Even GuideClaude Code Prompt Caching: The Token Discount Most People Never Turn OnRun a Team of AI Agents in Parallel with Git WorktreesPrompt Injection in Coding Agents: How to Not Get Pwned
speedy_devvkoen_salo
Blog/Handbook/Workflow/Adding Stripe Payments With Claude Code

Ajouter les paiements Stripe avec Claude Code

Branche Stripe Checkout, les webhooks et le portail client dans une app Next.js avec Claude Code. Du premier prompt au paiement en prod en une seule session.

Arrête de tout configurer. Place à la construction.

Des templates SaaS avec orchestration IA.

Published May 3, 20269 min readHandbook hubWorkflow index

Le problème : L'intégration Stripe a 7 pièces mobiles : le checkout, les webhooks, le portail client, les variables d'environnement, les clés de test, les clés live, et la CLI. La plupart des tutos en couvrent trois et te laissent déboguer le reste à minuit.

La victoire rapide : Ajoute le serveur MCP Stripe à Claude Code en une commande pour que Claude puisse consulter les clients, les prix et les abonnements en temps réel pendant que tu construis :

claude mcp add --transport http stripe https://mcp.stripe.com/

Cette seule ligne donne à Claude un accès direct à ton compte Stripe. Il peut lire les données en direct, vérifier que tes produits existent, et attraper les erreurs de config avant qu'elles n'atteignent ton gestionnaire de webhooks.

Ce qu'il te faut avant de commencer

Trois choses doivent être en place.

Un compte Stripe avec au moins un produit et un prix créés. Tu peux faire créer ça à Claude via le serveur MCP sans toucher au Dashboard. Une fois le MCP connecté, un prompt du genre « create a product called Pro Plan with a $29/month recurring price » suffit.

Claude Code avec le MCP Stripe connecté (commande au-dessus). L'alternative, c'est le Skill best-practices de Stripe, qui injecte la documentation Stripe dans ta session :

npx skills add https://docs.stripe.com --yes

Le serveur MCP est le meilleur choix pour le développement actif. Claude peut l'appeler en cours de session pour lister tes prix, retrouver un client par email, récupérer le statut actuel d'un abonnement, ou vérifier que ton secret de webhook correspond à ce que le Dashboard affiche. Le Skill ne te donne que du contexte de documentation. Il n'interroge pas ton compte.

Les deux ne s'excluent pas mutuellement. Certaines équipes utilisent les deux : MCP pour les requêtes en direct, Skill pour les conseils de bonnes pratiques. Le MCP avec une clé d'API restreinte (rk_test_...) est le setup le plus sûr en mode test parce que les clés restreintes limitent les objets Stripe que Claude peut toucher.

Quatre variables d'environnement dans ton fichier .env.local :

STRIPE_SECRET_KEY=sk_test_...
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...
NEXT_PUBLIC_URL=http://localhost:3000

STRIPE_SECRET_KEY ne touche jamais le client. NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY peut être exposée sans risque. STRIPE_WEBHOOK_SECRET vient de la CLI Stripe quand tu démarres le transfert d'événements en local (couvert dans la section tests). NEXT_PUBLIC_URL alimente tes paramètres success_url et return_url.

Checkout Sessions vs Payment Intents

Deux API Stripe peuvent encaisser un paiement. Choisir la mauvaise ajoute des semaines de boulot.

Les Checkout Sessions (stripe.checkout.sessions.create()) redirigent l'utilisateur vers une page hébergée par Stripe ou un formulaire intégré sur ton domaine. Stripe gère la saisie de carte, le 3D Secure, Apple Pay, l'affichage de la devise, et les taxes. Pour la plupart des produits SaaS, c'est le bon choix. Les achats uniques comme les abonnements passent par là.

Les Payment Intents (stripe.paymentIntents.create()) sont de plus bas niveau. Tu construis le formulaire toi-même avec Stripe Elements, tu collectes les données de carte, et tu appelles l'API. Plus de contrôle, plus de code, plus de maintenance. Ne l'utilise que quand tu as besoin d'un tunnel de paiement entièrement custom qu'une page hébergée ne peut pas offrir.

Le pattern privilégié en 2026 pour les Checkout Sessions, c'est l'Embedded Checkout : ui_mode: 'embedded' garde l'utilisateur sur ton domaine, utilise les composants EmbeddedCheckoutProvider et EmbeddedCheckout de @stripe/react-stripe-js, et renvoie vers une return_url que tu définis. Le Hosted Checkout (redirection vers stripe.com) marche toujours, mais c'est vers l'Embedded que Stripe oriente les nouvelles intégrations.

Construire le tunnel de paiement

Demande à Claude de générer la route, puis vérifie le param mode avant de livrer.

Un bon prompt à donner à Claude ici, c'est : « Build me a Stripe Checkout Sessions route in app/api/checkout/route.ts. Use mode: payment for one-time purchases, return the session URL as JSON, and read all URLs from environment variables. »

Pour un achat unique, la route ressemble à ça :

// app/api/checkout/route.ts
import { NextResponse } from 'next/server'
import Stripe from 'stripe'

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
  apiVersion: '2024-11-20.acacia',
})

export async function POST(request: Request) {
  const { priceId } = await request.json()

  const session = await stripe.checkout.sessions.create({
    mode: 'payment',
    line_items: [{ price: priceId, quantity: 1 }],
    success_url: `${process.env.NEXT_PUBLIC_URL}/success?session_id={CHECKOUT_SESSION_ID}`,
    cancel_url: `${process.env.NEXT_PUBLIC_URL}/pricing`,
  })

  return NextResponse.json({ url: session.url })
}

Pour un abonnement, change exactement une chose. Mets mode: 'subscription' au lieu de mode: 'payment'. Ton priceId doit pointer vers un prix récurrent (pas un prix unique) dans Stripe. Tout le reste de la route reste identique.

Pour passer à l'Embedded Checkout, ajoute ui_mode: 'embedded' et remplace success_url par return_url. La réponse renvoie session.client_secret au lieu de session.url, que l'EmbeddedCheckoutProvider utilise côté frontend.

Les webhooks : la partie que tout le monde rate

Les webhooks, c'est là où Stripe te répond. Chaque décision de provisionnement (accorder l'accès, le révoquer, envoyer un reçu) devrait vivre dans le gestionnaire de webhooks, pas dans la redirection de succès du checkout. Les utilisateurs ferment des onglets et cliquent sur précédent. La redirection n'est pas fiable. Le webhook se déclenche toujours.

Le souci critique dans l'App Router de Next.js, c'est le parsing du body brut. La vérification de signature de Stripe (stripe.webhooks.constructEvent) a besoin du body de requête brut sous forme de chaîne. L'App Router parse le body avant que ton gestionnaire ne le voie. Si tu appelles request.json(), le flux est consommé et la vérification échoue à tous les coups.

Donne à Claude la contrainte exacte : « Build a Stripe webhook handler at app/api/stripe-webhook/route.ts. It must use request.text() for the raw body, not request.json(), and verify the signature before processing any events. »

Utilise request.text() à la place :

// app/api/stripe-webhook/route.ts
import { NextResponse } from 'next/server'
import Stripe from 'stripe'

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
  apiVersion: '2024-11-20.acacia',
})

export async function POST(request: Request) {
  const rawBody = await request.text()
  const sig = request.headers.get('stripe-signature')!

  let event: Stripe.Event

  try {
    event = stripe.webhooks.constructEvent(
      rawBody,
      sig,
      process.env.STRIPE_WEBHOOK_SECRET!
    )
  } catch (err) {
    return NextResponse.json(
      { error: 'Webhook signature verification failed' },
      { status: 400 }
    )
  }

  switch (event.type) {
    case 'checkout.session.completed': {
      const session = event.data.object as Stripe.Checkout.Session
      // Provision access, send welcome email
      await grantAccess(session.customer as string)
      break
    }
    case 'customer.subscription.updated': {
      const sub = event.data.object as Stripe.Subscription
      // Update tier in DB
      await updateSubscription(sub.customer as string, sub.status)
      break
    }
    case 'customer.subscription.deleted': {
      const sub = event.data.object as Stripe.Subscription
      // Revoke access
      await revokeAccess(sub.customer as string)
      break
    }
    case 'invoice.payment_failed': {
      const invoice = event.data.object as Stripe.Invoice
      // Send dunning email, flag in DB
      await handleFailedPayment(invoice.customer as string)
      break
    }
  }

  return NextResponse.json({ received: true })
}

Les quatre événements à gérer au minimum sont dans le tableau ci-dessous. Le reste peut s'ajouter au fur et à mesure que ta logique de facturation grossit.

ÉvénementQuand il se déclencheAction
checkout.session.completedPaiement ou abonnement démarréProvisionner l'accès, envoyer l'email de bienvenue
customer.subscription.updatedChangement de plan, renouvellement, fin d'essaiMettre à jour le tier en base
customer.subscription.deletedRésiliationRévoquer l'accès
invoice.payment_failedÉchec d'un prélèvement récurrentEnvoyer l'email de relance, signaler en base

Une dernière chose : cette route doit être exclue de tout middleware Next.js qui lit le body, et elle ne doit pas être enveloppée dans les contrôles d'authentification de ton app. Stripe lui poste une requête non authentifiée. Protège-la uniquement par la vérification de signature.

Configuration du portail client

Le portail client permet aux utilisateurs de gérer eux-mêmes leur abonnement : résilier, mettre à jour les infos de paiement, voir les factures. Une étape coince la plupart des devs.

Tu dois configurer le portail dans le Dashboard Stripe avant de créer la moindre session de portail. Sans configuration sauvegardée, chaque appel billingPortal.sessions.create() renvoie une erreur. L'URL de configuration en mode test est https://dashboard.stripe.com/test/settings/billing/portal. Le mode live a sa propre URL distincte à https://dashboard.stripe.com/settings/billing/portal. Les deux demandent une configuration avant de déployer.

L'étape de configuration, c'est là que tu décides quelles actions les utilisateurs ont le droit de faire : résilier leur abonnement, mettre à jour leur moyen de paiement, changer de plan, télécharger les factures. Règle ces options dans le Dashboard, sauvegarde la configuration, et ensuite tes appels d'API marcheront.

Une fois configurée, la route pour créer une session est courte :

// app/api/portal/route.ts
import { NextResponse } from 'next/server'
import Stripe from 'stripe'

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
  apiVersion: '2024-11-20.acacia',
})

export async function POST(request: Request) {
  const { customerId } = await request.json()

  const session = await stripe.billingPortal.sessions.create({
    customer: customerId,
    return_url: `${process.env.NEXT_PUBLIC_URL}/account`,
  })

  return NextResponse.json({ url: session.url })
}

Ton frontend redirige vers session.url. L'utilisateur voit sa page de facturation Stripe, fait ses changements, et revient sur /account une fois terminé. Les changements se déclenchent sous forme d'événements customer.subscription.updated ou customer.subscription.deleted, que ton gestionnaire de webhooks couvre déjà.

Note : les configurations de portail en mode test et en mode live sont complètement séparées. Configurer le portail en mode test ne le met pas en place pour le mode live. Repasse par les mêmes étapes de configuration dans les deux environnements avant de passer en prod.

Tester le flux complet

La CLI Stripe transfère les événements en direct depuis Stripe vers ton serveur local. Lance ça dans un terminal séparé avant de tester le moindre paiement :

stripe listen --forward-to localhost:3000/api/stripe-webhook

La CLI affiche un secret de signature de webhook au démarrage. Cette valeur va dans STRIPE_WEBHOOK_SECRET dans ton .env.local. Elle change à chaque redémarrage du listener, alors ne la code pas en dur.

Pour déclencher un événement précis sans cliquer à travers un formulaire de paiement, utilise stripe trigger :

stripe trigger checkout.session.completed
stripe trigger customer.subscription.deleted
stripe trigger invoice.payment_failed

Cartes de test pour différents scénarios :

ScénarioNuméro de carte
Paiement réussi4242 4242 4242 4242
Refusé4000 0000 0000 0002
3D Secure requis4000 0025 0000 3155
Fonds insuffisants4000 0000 0000 9995

Utilise n'importe quelle date d'expiration future, n'importe quel CVC à 3 chiffres, et n'importe quel code postal. Le numéro de carte est la seule valeur qui change le résultat.

La séquence de test recommandée, c'est : démarrer le listener CLI, ouvrir ta page de paiement, faire un paiement avec la carte 4242 4242 4242 4242, regarder l'événement checkout.session.completed arriver dans ton terminal, et vérifier que ton gestionnaire a bien tourné (vérifie la base ou les logs). Ensuite, déclenche stripe trigger invoice.payment_failed pour confirmer que ton chemin de relance marche sans attendre un vrai échec de prélèvement. Garde la carte 3D Secure (4000 0025 0000 3155) pour la fin. Stripe redirige par une étape d'authentification que ton frontend doit gérer. Si la redirection échoue en silence, la session ne se termine jamais et aucun webhook ne se déclenche.

Checklist de passage en prod

Passer du mode test au mode live, c'est quatre étapes, pas un seul changement de clé.

D'abord, remplace tes clés de test (sk_test_, pk_test_) par les clés live (sk_live_, pk_live_) dans les variables d'environnement de ta production.

Ensuite, configure le portail client en mode live à https://dashboard.stripe.com/settings/billing/portal. Le mode test et le mode live ont des configurations de portail complètement séparées. Ce que tu règles en mode test ne se reporte pas.

Troisièmement, règle ton endpoint de webhook dans le Dashboard Stripe vers ton URL de production. Va dans Developers > Webhooks > Add endpoint et pointe-le vers https://yourdomain.com/api/stripe-webhook. Copie le secret de signature de webhook live et mets-le comme STRIPE_WEBHOOK_SECRET en production.

Quatrièmement, confirme tes ID de prix. Les prix du mode test (price_test_...) n'existent pas en mode live. Tout ID de prix codé en dur doit être mis à jour vers des ID de prix live ou lu depuis les variables d'environnement.

Fais un vrai paiement avec une vraie carte (puis rembourse-le) avant de considérer l'intégration terminée. Le trigger CLI est bien pour tester les gestionnaires, mais rien ne confirme le chemin complet comme un vrai prélèvement.

Ce que Build This Now livre préconstruit

Écrire et déboguer ce flux prend une journée entière pour la plupart des devs. L'edge function de checkout de Stripe, le gestionnaire de webhooks, la route du portail client, et les quatre variables d'environnement sont prébranchés dans Build This Now dès le premier jour. L'intégration se déploie sur les Supabase Edge Functions, testée et fonctionnelle, avant que tu n'écrives ta première fonctionnalité custom.

Stripe n'est pas la partie difficile. Brancher chaque pièce dans le bon ordre, si. Une fois que tu l'as fait une fois, tu sais où sont les trous.

Continue in Workflow

  • Commerce agentique : comment construire une app que les agents IA peuvent payer
    Un guide en français simple du commerce agentique en 2026 : ce que font x402, ACP et le Machine Payments Protocol, plus un pas-à-pas d'un week-end pour livrer une API payante que les agents IA peuvent acheter.
  • Bonnes pratiques Claude Code
    Cinq habitudes séparent les ingénieurs qui livrent avec Claude Code : les PRDs, les règles CLAUDE.md modulaires, les slash commands personnalisés, les resets /clear, et un état d'esprit d'évolution du système.
  • Le mode auto de Claude Code
    Un second modèle Sonnet examine chaque appel d'outil Claude Code avant qu'il s'exécute. Ce que le mode auto bloque, ce qu'il autorise, et les règles d'autorisation qu'il place dans tes paramètres.
  • Channels, Routines, Teleport, Dispatch
    Les quatre fonctionnalités Claude Code livrées par Anthropic en mars et avril 2026 qui transforment le CLI en une couche de coordination orientée événements, entre téléphone, web et desktop.
  • Claude Code 1M Context in Practice: When Bigger Isn't Better
    The 1M-token context window is GA at flat pricing, but bigger isn't always better. A decision framework, token-cost math, and when to use /compact, subagents, and dynamic workflows instead.
  • Claude Code Channels
    Connecte Claude Code à Telegram, Discord ou iMessage avec des serveurs MCP plugin. Walkthroughs de setup et workflows mobiles async qui valent la peine d'être configurés.

More from Handbook

  • Principes de base de l'agent
    Cinq façons de construire des agents spécialisés dans le code Claude : Sous-agents de tâches, .claude/agents YAML, commandes slash personnalisées, personas CLAUDE.md, et invites de perspective.
  • L'ingénierie du harness agent
    Le harness, c'est toutes les couches autour de ton agent IA sauf le modèle lui-même. Découvre les cinq leviers de contrôle, le paradoxe des contraintes, et pourquoi le design du harness détermine les performances de l'agent bien plus que le modèle.
  • Patterns d'agents
    Orchestrateur, fan-out, chaîne de validation, routage par spécialiste, raffinement progressif, et watchdog. Six formes d'orchestration pour câbler des sub-agents Claude Code.
  • Meilleures pratiques des équipes d'agents
    Patterns éprouvés pour les équipes d'agents Claude Code. Prompts de création riches en contexte, tâches bien calibrées, propriété des fichiers, mode délégué, et correctifs v2.1.33-v2.1.45.

Arrête de tout configurer. Place à la construction.

Des templates SaaS avec orchestration IA.

Le mode auto de Claude Code

Un second modèle Sonnet examine chaque appel d'outil Claude Code avant qu'il s'exécute. Ce que le mode auto bloque, ce qu'il autorise, et les règles d'autorisation qu'il place dans tes paramètres.

Feedback Loops

Donne à Claude Code un seul prompt qui écrit du code, lance ta commande de test ou de dev, lit la sortie, corrige ce qui casse, et boucle jusqu'à ce que la suite soit au vert.

On this page

Ce qu'il te faut avant de commencer
Checkout Sessions vs Payment Intents
Construire le tunnel de paiement
Les webhooks : la partie que tout le monde rate
Configuration du portail client
Tester le flux complet
Checklist de passage en prod
Ce que Build This Now livre préconstruit

Arrête de tout configurer. Place à la construction.

Des templates SaaS avec orchestration IA.