Paiements
Stripe avec 5 plans, 16 modules à la carte, 6 bundles, et système freemium.
Configuration Stripe
Variables d'environnement essentielles
# Clés API
STRIPE_SECRET_KEY="sk_test_xxxx" # Serveur uniquement
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY="pk_test_xxxx" # Client
STRIPE_WEBHOOK_SECRET="whsec_xxxx" # Validation webhooksFichiers clés
| Fichier | Rôle |
|---|---|
src/lib/stripe-plan.ts | Plans, prix, modules, bundles |
src/lib/freemium/freemium-limits.ts | Quotas par plan |
src/lib/freemium/freemium-guard.ts | Guard centralisé (checkFreemiumLimit) |
src/app/api/webhooks/stripe/ | Webhooks Stripe |
src/app/api/checkout/ | Checkout sessions |
Plans
HeartCo propose 5 plans avec une tarification EUR et CHF :
Tarification EUR
| Plan | Nom commercial | Mensuel | Annuel | Utilisateurs inclus |
|---|---|---|---|---|
| FREE | Pulsation Gratuit | 0 € | 0 € | 1 |
| STARTER | Pulsation | 15 € | 12 €/mois | 1 |
| CORE | Rythme | 34 € | 27 €/mois | 3 |
| BUSINESS | Battement | 69 € | 55 €/mois | 10 |
| ENTERPRISE | Cœur+ | 139 € | 111 €/mois | 50 |
Réduction annuelle : ~20% sur tous les plans.
Tarification CHF (Suisse)
| Plan | Mensuel | Annuel |
|---|---|---|
| STARTER | 17 CHF | 14 CHF/mois |
| CORE | 39 CHF | 31 CHF/mois |
| BUSINESS | 79 CHF | 63 CHF/mois |
| ENTERPRISE | 159 CHF | 127 CHF/mois |
Utilisateurs supplémentaires
| Mensuel | Annuel | |
|---|---|---|
| EUR | 9 € | 7 €/mois |
| CHF | 10 CHF | 8 CHF/mois |
Période d'essai
- Durée : 14 jours
- Plan : Battement (BUSINESS) complet
- Carte bancaire : non requise
- À l'expiration : downgrade automatique vers FREE
- Crons :
trial-expiry(downgrade) +trial-reminder(rappels à J-7 et J-2)
Modules à la carte
16 modules achetables individuellement, en complément du plan :
| Module | ID | Mensuel | Annuel |
|---|---|---|---|
| Devis | MODULE_DEVIS | 8 € | 6 € |
| Gestion financière | MODULE_COMPTABILITE | 12 € | 10 € |
| Notes de frais | MODULE_NOTES_FRAIS | 8 € | 6 € |
| Relances automatiques | MODULE_RELANCES | 6 € | 5 € |
| CRM & Pipeline | MODULE_CRM | 10 € | 8 € |
| Catalogue produits | MODULE_PRODUITS | 7 € | 6 € |
| Fournisseurs | MODULE_FOURNISSEURS | 5 € | 4 € |
| Rendez-vous | MODULE_RENDEZ_VOUS | 7 € | 6 € |
| Bons de travail | MODULE_BONS_TRAVAIL | 9 € | 7 € |
| Rapports terrain | MODULE_RAPPORTS_TERRAIN | 9 € | 7 € |
| Itinéraires optimisés | MODULE_ITINERAIRES | 5 € | 4 € |
| Gestion équipe | MODULE_EQUIPE | 7 € | 6 € |
| Feuilles de temps | MODULE_FEUILLES_TEMPS | 6 € | 5 € |
| Fiches de paie | MODULE_FICHES_PAIE | 10 € | 8 € |
| Congés & Absences | MODULE_RH_CONGES | 6 € | 5 € |
| Assistant IA | MODULE_CHATBOT_IA | 9 € | 7 € |
Modules inclus par plan
| Plan | Modules inclus |
|---|---|
| FREE | Aucun |
| STARTER | Devis |
| CORE | Devis, CRM, Relances, Produits, Fournisseurs |
| BUSINESS | Core + Comptabilité, Notes de frais, Équipe, Congés, Bons de travail, Feuilles de temps, Assistant IA |
| ENTERPRISE | Tous les modules |
Bundles
6 packs thématiques regroupant plusieurs modules :
| Bundle | Mensuel | Annuel | Plan requis |
|---|---|---|---|
| Pack BTP | 29 € | 23 € | BUSINESS |
| Pack Freelance Pro | 19 € | 15 € | STARTER |
| Pack Agence Services | 24 € | 19 € | CORE |
| Pack Commerce & Retail | 24 € | 19 € | CORE |
| Pack Entreprise Complète | 39 € | 31 € | BUSINESS |
| Pack Marketing Pro | 19 € | 15 € | CORE |
Quotas freemium
Chaque plan impose des limites d'utilisation. Le système "check before, increment after" vérifie les quotas avant chaque action.
| Feature | FREE | TRIAL | STARTER | BUSINESS | ENTERPRISE |
|---|---|---|---|---|---|
| Factures/mois | 3 | 15 | 50 | ∞ | ∞ |
| Devis/mois | 2 | 10 | 30 | ∞ | ∞ |
| Clients (total) | 10 | 30 | 200 | ∞ | ∞ |
| Produits (total) | 10 | 50 | 200 | ∞ | ∞ |
| Deals CRM (total) | 5 | 20 | ∞ | ∞ | ∞ |
| Bons de travail/mois | 3 | 15 | ∞ | ∞ | ∞ |
| Rapports/mois | 2 | 10 | ∞ | ∞ | ∞ |
| Fournisseurs (total) | 3 | 15 | ∞ | ∞ | ∞ |
| Membres d'équipe | 1 | 5 | 10 | 30 | ∞ |
| Événements calendrier/mois | 10 | ∞ | ∞ | ∞ | ∞ |
| Messages chatbot/jour | 5 | 30 | 100 | ∞ | ∞ |
| Idées/mois | 3 | ∞ | ∞ | ∞ | ∞ |
| Congés/mois | 1 | 5 | ∞ | ∞ | ∞ |
| Notes de frais/mois | 2 | 10 | ∞ | ∞ | ∞ |
| Feuilles de temps/mois | 5 | 30 | ∞ | ∞ | ∞ |
| Rendez-vous/mois | 3 | 20 | ∞ | ∞ | ∞ |
| Générations image/mois | 0 | 10 | 10 | 50 | 200 |
Les quotas mensuels sont réinitialisés le 1er de chaque mois via le cron
reset-usage.
Pattern "check before, increment after"
// Dans le router tRPC
const guard = await checkFreemiumLimit(ctx, "invoices");
if (!guard.allowed) {
throw new TRPCError({
code: "FORBIDDEN",
message: `Quota factures atteint (${guard.used}/${guard.limit})`,
});
}
// ... créer la facture ...
// Incrémenter APRÈS le succès (pas avant)
await ctx.db.subscription.update({
where: { organizationId: ctx.session.user.organizationId },
data: { invoicesUsed: { increment: 1 } },
});Webhooks Stripe
Les webhooks Stripe sont gérés dans src/app/api/webhooks/stripe/. Événements principaux :
| Événement | Action |
|---|---|
checkout.session.completed | Active l'abonnement |
customer.subscription.updated | Met à jour le plan |
customer.subscription.deleted | Downgrade vers FREE |
invoice.payment_succeeded | Marque le paiement |
invoice.payment_failed | Notification d'échec |
Modifier les plans
Changer un prix
- Modifier dans
src/lib/stripe-plan.ts:
PLAN_PRICING_EUR: {
CORE: { monthly: 39, annual: 31 }, // Nouveau prix
}- Créer de nouveaux Price IDs dans le dashboard Stripe
- Mettre à jour les variables d'environnement
STRIPE_PRICE_*
Ajouter un module à la carte
- Ajouter dans
MODULE_PRICES_EURdesrc/lib/stripe-plan.ts - Créer les Price IDs dans Stripe (monthly + annual)
- Ajouter les env vars
STRIPE_PRICE_MODULE_* - Ajouter dans
STRIPE_PRICE_MAP
Changer les quotas freemium
Modifier PLAN_LIMITS dans src/lib/freemium/freemium-limits.ts. Utiliser -1 pour "illimité".
Fonctions utilitaires
import {
getPlanFromPriceId,
isModulePriceId,
isBundlePriceId,
isPlanPriceId,
getPriceIdForCurrency,
} from "~/lib/stripe-plan";
// Identifier un Price ID
getPlanFromPriceId("price_xxx"); // "CORE" | null
isModulePriceId("price_xxx"); // true/false
isBundlePriceId("price_xxx"); // true/false
// Obtenir un Price ID par devise
getPriceIdForCurrency("CORE", "monthly", "EUR"); // "price_xxx"
getPriceIdForCurrency("CORE", "annual", "CHF"); // "price_yyy"