Paiements Stripe : connecte, sync et gère tes produits

Crée ton compte Stripe, configure clés, SDK serveur, et synchronise produits Prisma en un clic dans React Router. Maîtrise paiements et tarifs sans stress.

3 min read
Déverrouillez votre potentiel

avec React Router 7

Vous en avez marre de...

❌ perdre du temps à chercher des informations éparpillées
❌ ne pas avoir de retour sur votre progression
Assistant IA spécialisé

Posez vos questions 24/7 à notre IA experte en React Router 7

Quiz interactifs

Validez vos acquis avec des quiz personnalisés et un feedback instantané

9 modules
72 leçons
Accès à vie
299.49
-35%

Crée un compte Stripe dans sa propre organisation

  1. Connecte-toi sur https://dashboard.stripe.com.
  2. Settings → Accounts → Create a new account.
  3. Renseigne : • Nom : Shop Router • Pays : France • Business type : Services numériques
  4. Décoche Tax collection pour éviter des frais superflus.

Stripe génère immédiatement un tableau de bord test et live.

Ajoute les clés API à .env

.env
1
# mode test - ne jamais pousser en prod
2
STRIPE_PUBLISHABLE_KEY=pk_test_xxx
3
STRIPE_SECRET_KEY=sk_test_xxx

Gardes-les hors Git : .env figure déjà dans .gitignore.

Installe et configure le SDK côté serveur

install.sh
1
npm add stripe
app/server/stripe.server.ts
1
import Stripe from "stripe";
2
3
export const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
4
apiVersion: "2023-10-16",
5
});

Pourquoi ? – instance unique ; – version figée ➜ pas de breaking change surprise.

Synchronise un produit Prisma → Stripe

app/server/stripe-products.server.ts
1
import { prisma } from "~/server/db.server";
2
import { stripe } from "./stripe.server";
3
4
export async function syncProductWithStripe(productId: string) {
5
const product = await prisma.product.findUnique({
6
where: { id: productId },
7
include: { images: { take: 1 } },
8
});
9
if (!product) throw new Error("Product not found");
10
11
/* 1 - Produit Stripe */
12
const stripeProduct =
13
product.stripeProductId
14
? await stripe.products.retrieve(product.stripeProductId)
15
: await stripe.products.create({
16
name: product.name,
17
description: product.description ?? "",
18
images: product.images.map((i) => i.url),
19
active: product.isActive,
20
});
21
22
/* 2 - Prix Stripe */
23
await syncStripePrice({ product, stripeProductId: stripeProduct.id });
24
25
/* 3 - Sauvegarde en DB */
26
await prisma.product.update({
27
where: { id: product.id },
28
data: { stripeProductId: stripeProduct.id },
29
});
30
}
31
32
async function syncStripePrice({
33
product,
34
stripeProductId,
35
}: {
36
product: { priceCents: number; stripePriceId?: string };
37
stripeProductId: string;
38
}) {
39
const amount = product.priceCents;
40
41
/* Stripe interdit la modif direct d'un prix */
42
if (product.stripePriceId) {
43
await stripe.prices.update(product.stripePriceId, { active: false });
44
}
45
46
const price = await stripe.prices.create({
47
product: stripeProductId,
48
unit_amount: amount,
49
currency: "eur",
50
});
51
52
await prisma.product.update({
53
where: { stripeProductId },
54
data: { stripePriceId: price.id },
55
});
56
}

Explications brèves :

  • Si l’ID Stripe existe : retrieve, sinon create.
  • Un changment de montant ➜ ancien prix archivé, nouveau créé.
  • On stocke les IDs Stripe dans Prisma (stripeProductId, stripePriceId).

Ajoute le bouton “Synchroniser Stripe” dans l’admin

app/routes/admin+/products.$productSlug.tsx
1
import { syncProductWithStripe } from "~/server/stripe-products.server";
2
3
export const action = async ({ params }: Route.ActionArgs) => {
4
await syncProductWithStripe(params.productSlug);
5
return redirect(`/admin/products/${params.productSlug}`);
6
};
{8} app/routes/admin+/products.$productSlug.tsx
1
<fetcher.Form method="POST">
2
<Button
3
name="intent"
4
value="sync-stripe"
5
isLoading={fetcher.state === "submitting"}
6
>
7
Synchroniser Stripe
8
</Button>
9
</fetcher.Form>

Le spinner affiche fetcher.state === "submitting" ; l’UI reste sur place.

Synchronisation en masse depuis la liste

app/routes/admin+/products.index.tsx
1
export async function action() {
2
const ids = await prisma.product.findMany({ select: { id: true } });
3
for (const { id } of ids) await syncProductWithStripe(id);
4
return redirect("/admin/products");
5
}
1
<fetcher.Form method="POST">
2
<Button isLoading={fetcher.state==="submitting"}>Sync catalogue</Button>
3
</fetcher.Form>

Supprime aussi le produit côté Stripe

app/server/stripe-products.server.ts
1
export async function deleteStripeProduct(stripeProductId?: string) {
2
if (!stripeProductId) return;
3
4
const prices = await stripe.prices.list({ product: stripeProductId });
5
for (const p of prices.data) await stripe.prices.update(p.id, { active: false });
6
7
await stripe.products.update(stripeProductId, { active: false });
8
}

Appel :

1
await deleteStripeProduct(product.stripeProductId);
2
await prisma.product.delete({ where: { id: product.id } });

Ce que tu viens d’accomplir

  • Création d’un compte Stripe dédié à l’appli.
  • Stockage sécurisé des clés dans .env.
  • SDK Stripe typé côté serveur.
  • Synchronisation produit ↔ prix ↔ image en un clic.
  • Archivage automatique des anciens prix (historique préservé).
  • Nettoyage Stripe lors d’une suppression produit.

Ton catalogue est désormais miroir de Stripe ; prêt à lancer une session Checkout et encaisser tes premiers paiements. 🚀

Premium
Quiz interactif
Testez vos connaissances et validez votre compréhension du module avec notre quiz interactif.
1

Comprendre les concepts fondamentaux

Quelle est la principale différence entre les composants client et serveur dans React ?

Les composants client s'exécutent uniquement dans le navigateur
Les composants serveur peuvent utiliser useState
Les composants client sont plus rapides
Il n'y a aucune différence significative
2

Optimisation des performances

Quelle technique est recommandée pour éviter les rendus inutiles dans React ?

Utiliser React.memo pour les composants fonctionnels
Ajouter plus d'états locaux
Éviter d'utiliser les props
Toujours utiliser les class components
3

Architecture des données

Quel hook permet de gérer les effets de bord dans un composant React ?

useEffect
useState
useMemo
useContext
4

Gestion des erreurs

Comment implémenter la gestion des erreurs pour les requêtes API dans React ?

Utiliser try/catch avec async/await
Ignorer les erreurs
Toujours afficher un message d'erreur
Rediriger l'utilisateur
5

Déploiement et CI/CD

Quelle est la meilleure pratique pour déployer une application React en production ?

Utiliser un service CI/CD comme GitHub Actions
Copier les fichiers manuellement via FTP
Envoyer le code source complet
Ne jamais mettre à jour l'application

Débloquez ce quiz et tous les autres contenus premium en achetant ce cours