L’intégration de Stripe avec Next.js 15 permet de créer des applications web dynamiques et réactives qui gèrent les paiements en ligne. Stripe offre des fonctionnalités puissantes pour la gestion des paiements récurrents, et Next.js est un excellent choix pour construire des applications modernes. Dans cet article, nous allons explorer comment configurer Stripe avec Next.js, en nous concentrant sur la création de sessions de paiement, la gestion des utilisateurs et l’implémentation d’un Webhook pour suivre les événements de paiement.

1. Prérequis

Avant de commencer, il est essentiel de s’assurer que vous disposez des éléments suivants :

  • Node.js : Veillez à ce que Node.js soit installé sur votre machine.
  • Next.js 15 : Vous pouvez soit créer un nouveau projet Next.js, soit utiliser un projet existant.
  • Stripe : Créez un compte sur Stripe et obtenez vos clés API.
  • Prisma : Nous allons utiliser Prisma pour la gestion de la base de données.

2. Installation des dépendances

Pour intégrer Stripe et Prisma, commencez par installer les packages nécessaires. Exécutez les commandes suivantes dans votre terminal :

npm install stripe
npm install prisma --save-dev
npm install @prisma/client
npm install @clerk/nextjs

Ces commandes installeront Stripe pour la gestion des paiements et Prisma pour la gestion de la base de données.

3. Création du fichier stripe.ts

Tout d’abord, nous allons créer un fichier stripe.ts pour initialiser la connexion avec l’API Stripe. Voici le code nécessaire :

import Stripe from "stripe";export const stripe = new Stripe(process.env.STRIPE_KEY_SECRET as string, {
typescript: true,
});export const getStripeSession = async({priceId, domainUrl, customerId}:{priceId: string, domainUrl: string, customerId: string}) => {
const session = await stripe.checkout.sessions.create({
customer: customerId,
mode: "subscription",
billing_address_collection: "auto",
line_items: [{price: priceId, quantity: 1}],
payment_method_types: ["card"],
customer_update: {
address: "auto",
name: "auto",
},
success_url: `${domainUrl}/dashboard/payment/success`,
cancel_url: `${domainUrl}/dashboard/payment/cancel`,
});
return session.url as string;
}

Dans ce code, nous avons initialisé Stripe avec la clé secrète stockée dans les variables d’environnement. De plus, la fonction getStripeSession crée une nouvelle session de paiement pour un abonnement, incluant les URLs de succès et d’annulation.

4. Mise en place des actions Stripe

Ensuite, il est important de créer les actions nécessaires pour gérer les abonnements des utilisateurs. Voici le code pour notre fichier actionsStripe.ts :

"use server"
import { prisma } from "@/lib/db";
import { getStripeSession } from "@/lib/stripe";
import { redirect } from "next/navigation";
import { getUser } from "./actionsUsers";
import { stripe } from "@/lib/stripe";export const getDataStripeUser = async (userId: string) => {
const data = await prisma.subscription.findUnique({
where: {
userId: userId,
},
select: {
status: true,
user: {
select: {
stripeCustomerId: true
}
}
}
});return data;
};export const createSubscription = async () => {
const user = await getUser();
if (!user) {
throw new Error("User not found.");
}const dbUser = await prisma.user.findUnique({
where: {
clerkUserId: user.clerkUserId as string
},
select: {
stripeCustomerId: true
}
});if (!dbUser?.stripeCustomerId) {
throw new Error("User does not have a Stripe customer ID.");
}const subscriptionUrl = await getStripeSession({
customerId: dbUser.stripeCustomerId,
domainUrl: "http://localhost:3000",
priceId: process.env.STRIPE_API_ID as string
});return redirect(subscriptionUrl);
};export const createCustomerPortal = async () => {
const user = await getUser();
const session = await stripe.billingPortal.sessions.create({
customer: user?.stripeCustomerId as string,
return_url: "http://localhost:3000/dashboard/profile",
});
return redirect(session.url);
};

Dans ce fichier, nous avons plusieurs fonctions pour gérer les abonnements. La fonction createSubscription permet de créer un abonnement en récupérant l’utilisateur connecté et en créant une session de paiement. En outre, createCustomerPortal redirige l’utilisateur vers un portail de gestion des abonnements Stripe.

5. Gestion des utilisateurs

Par la suite, nous devons également gérer les utilisateurs dans notre application. Voici le code pour les actions utilisateurs dans actionsUsers.ts :

"use server"
import { prisma } from "@/lib/db";
import { redirect } from "next/navigation";
import { auth } from "@clerk/nextjs/server";export const addUserToDatabase = async (clerkUserId: string, name: string, email: string, image: string) => {
try {
const user = await prisma.user.upsert({
where: { clerkUserId },
update: {
name,
email,
image
},
create: {
clerkUserId,
name,
email,
image
},
});
return user;
} catch (error) {
console.error("Error adding user to database:", error);
throw error;
}
};export const getUser = async () => {
const { userId } = await auth();if (!userId) {
redirect("../");
}const user = await prisma.user.findUnique({
where: { clerkUserId: userId }
});return user;
};

Dans ce code, la fonction addUserToDatabase permet d’ajouter un utilisateur à la base de données ou de mettre à jour ses informations si l’utilisateur existe déjà. De plus, la fonction getUser récupère les informations de l’utilisateur connecté à l’aide de Clerk.

6. Configuration des modèles Prisma

Ensuite, pour stocker les informations des utilisateurs et leurs abonnements, nous devons configurer nos modèles Prisma. Voici les modèles que nous allons utiliser :

model User {
id              String       @id @default(cuid())
name String
email String
image String?
createdAt       DateTime     @default(now())
updatedAt       DateTime     @updatedAt
clerkUserId     String?      @unique
stripeCustomerId String? @unique
subscription Subscription[]
}model Subscription {
stripeSubscriptionId String @id @unique
interval String
status String
planId String
currentPeriodStart Int
currentPeriodEnd Int
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [clerkUserId])
userId String @unique
}

Ces modèles définissent les structures de données nécessaires pour gérer les utilisateurs et leurs abonnements. Plus précisément, le modèle User contient les informations de l’utilisateur, tandis que le modèle Subscription gère les abonnements liés à chaque utilisateur.

7. Configuration du Webhook Stripe

Ensuite, pour gérer les événements de Stripe, tels que les paiements réussis ou les abonnements créés, nous devons configurer un Webhook. Voici comment le mettre en place dans le fichier webhook.ts :

import { headers } from "next/headers";
import Stripe from "stripe";
import { stripe } from "@/lib/stripe";
import { prisma } from "@/lib/db";export async function POST(req: Request) {
const body = await req.text();
const headersList = await headers();
const signature = headersList.get("Stripe-signature") as string;let event: Stripe.Event;try {
event = stripe.webhooks.constructEvent(
body,
signature,
process.env.STRIPE_WEBHOOK_SECRET as string
);
} catch (error: unknown) {
return new Response('Erreur webhook stripe', { status: 400 });
}const session = event.data.object as Stripe.Checkout.Session;if (event.type === "checkout.session.completed") {
const subscription = await stripe.subscriptions.retrieve(
session.subscription as string
);
const customerId = String(session.customer);const user = await prisma.user.findUnique({
where: {
stripeCustomerId: customerId,
},
});if (!user) {
throw new Error("Utilisateur inexistant");
}await prisma.subscription.create({
data: {
stripeSubscriptionId: subscription.id,
userId: user.clerkUserId,
currentPeriodStart: subscription.current_period_start,
currentPeriodEnd: subscription.current_period_end,
status: subscription.status,
interval: subscription.items.data[0].plan.interval,
},
});
} else if (event.type === "customer.subscription.updated") {
const subscription = await stripe.subscriptions.retrieve(
session.subscription as string
);await prisma.subscription.update({
where: {
stripeSubscriptionId: subscription.id,
},
data: {
status: subscription.status,
},
});
}return new Response("Succès", { status: 200 });
}

Ce Webhook gère les événements de paiement et met à jour les informations dans la base de données. Par ailleurs, il vérifie également si l’utilisateur existe avant de créer un nouvel abonnement.

8. Test de l’intégration

Pour tester l’intégration, il est crucial d’utiliser les outils de développement de Stripe afin de simuler des événements. Vous pouvez également procéder à des transactions réelles en mode test pour valider l’ensemble du processus d’abonnement. Cela vous permettra de vous assurer que tout fonctionne comme prévu.

9. Conclusion

En conclusion, vous avez maintenant une intégration complète de Stripe avec Next.js 15, comprenant la création de sessions de paiement, la gestion des utilisateurs, la configuration de Prisma, et la gestion des Webhooks. Cette base peut être étendue avec des fonctionnalités supplémentaires, telles que la gestion des annulations ou la mise à jour des informations de facturation. Grâce à ces outils, vous êtes désormais prêt à gérer efficacement les paiements dans votre application Next.js. Pour approfondir vos connaissances en Next JS et maîtriser ces nouvelles fonctionnalités, n’hésitez pas à rejoindre ma formation dédiée à Next JS, où vous apprendrez à créer des applications performantes et réactives.

Newsletter

Vous souhaitez maîtriser les langages et outils du web ? Ne manquez aucune opportunité avec nos tutoriels, astuces et offres exclusives ! Inscrivez-vous dès maintenant pour recevoir des contenus de qualité, soigneusement sélectionnés pour vous, et boostez vos compétences. En vous inscrivant, vous recevrez une formation offerte ! 

Confirmez votre inscription via l'email qui vient de vous être envoyé. Vérifiez vos spams.