Retour au blog
20 avril 2026 Arthur Fabbri
Intégrer Stripe dans Next.js : du checkout aux webhooks
Session checkout, page succès, webhooks, Stripe CLI — guide complet pour accepter des paiements avec Stripe dans une app Next.js 15.
Stripe est LA référence pour les paiements en ligne. Voici comment l'intégrer proprement dans Next.js, de la session checkout à la gestion des webhooks.
Installation
npm install stripe @stripe/stripe-js
Variables d'environnement :
STRIPE_SECRET_KEY=sk_test_...
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...
1. Créer une session Checkout
// app/api/checkout/route.ts
import Stripe from "stripe";
import { NextRequest, NextResponse } from "next/server";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
export async function POST(req: NextRequest) {
const { priceId, quantity = 1 } = await req.json();
const session = await stripe.checkout.sessions.create({
payment_method_types: ["card"],
line_items: [{ price: priceId, quantity }],
mode: "payment", // ou "subscription" pour abonnement
success_url: `${process.env.NEXT_PUBLIC_SITE_URL}/success?session_id={CHECKOUT_SESSION_ID}`,
cancel_url: `${process.env.NEXT_PUBLIC_SITE_URL}/shop`,
locale: "fr",
});
return NextResponse.json({ url: session.url });
}
2. Bouton d'achat côté client
// components/buy-button.tsx
"use client";
import { useState } from "react";
export function BuyButton({ priceId }: { priceId: string }) {
const [loading, setLoading] = useState(false);
async function handleClick() {
setLoading(true);
const res = await fetch("/api/checkout", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ priceId }),
});
const { url } = await res.json();
window.location.href = url;
}
return (
<button
onClick={handleClick}
disabled={loading}
className="bg-primary text-white px-6 py-3 rounded-xl disabled:opacity-60"
>
{loading ? "Redirection…" : "Acheter"}
</button>
);
}
3. Page succès
// app/success/page.tsx
import Stripe from "stripe";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
interface Props {
searchParams: Promise<{ session_id?: string }>;
}
export default async function SuccessPage({ searchParams }: Props) {
const { session_id } = await searchParams;
if (!session_id) return <p>Session invalide.</p>;
const session = await stripe.checkout.sessions.retrieve(session_id, {
expand: ["line_items", "customer"],
});
return (
<div className="text-center py-24">
<div className="text-6xl mb-4">🎉</div>
<h1 className="text-2xl font-bold mb-2">Paiement confirmé !</h1>
<p>Merci pour votre achat. Un email de confirmation a été envoyé.</p>
<p className="text-muted mt-2">
Total : {(session.amount_total! / 100).toFixed(2)} €
</p>
</div>
);
}
4. Webhooks Stripe
Les webhooks sont essentiels pour mettre à jour votre BDD après un paiement.
// app/api/webhooks/stripe/route.ts
import Stripe from "stripe";
import { NextRequest, NextResponse } from "next/server";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
export async function POST(req: NextRequest) {
const body = await req.text();
const sig = req.headers.get("stripe-signature")!;
let event: Stripe.Event;
try {
event = stripe.webhooks.constructEvent(
body,
sig,
process.env.STRIPE_WEBHOOK_SECRET!
);
} catch {
return NextResponse.json({ error: "Signature invalide" }, { status: 400 });
}
switch (event.type) {
case "checkout.session.completed": {
const session = event.data.object as Stripe.Checkout.Session;
// Mettre à jour la BDD, envoyer un email, etc.
console.log("Paiement reçu :", session.customer_email);
break;
}
case "customer.subscription.deleted": {
// Révoquer l'accès
break;
}
}
return NextResponse.json({ received: true });
}
5. Tester avec Stripe CLI
# Installer Stripe CLI
stripe login
# Forwarder les webhooks en local
stripe listen --forward-to localhost:3000/api/webhooks/stripe
# Déclencher un événement test
stripe trigger checkout.session.completed
Carte de test : 4242 4242 4242 4242 — n'importe quelle date future, n'importe quel CVC.
Abonnements (mode subscription)
const session = await stripe.checkout.sessions.create({
mode: "subscription",
line_items: [{ price: "price_monthly_id", quantity: 1 }],
// ...
subscription_data: {
trial_period_days: 14, // essai gratuit
},
});
Conclusion
Stripe + Next.js = une stack de paiement robuste en quelques heures. Les points clés : toujours vérifier la signature webhook, ne jamais faire confiance au client pour valider les montants, et utiliser Stripe CLI pour tester localement.