Skip to main content
FIM One propose un pipeline de facturation Stripe complet derrière un modèle d’accès par instance. Les déploiements privés le laissent sur Pas d’abonnements et ne voient jamais l’interface de paiement. Les opérateurs qui souhaitent un catalogue choisissent Inclus + payant ou Payant uniquement et obtiennent Checkout hébergé, Customer Portal, cycle de vie d’abonnement piloté par webhook et application des quotas.
La valeur par défaut du logiciel est Pas d’abonnements (access_model = off, default_token_quota = 0 signifiant illimité). Les nouvelles installations et les auto-hébergements existants commencent là. Aucune interface de facturation n’apparaît jusqu’à ce qu’un administrateur choisisse une posture Stripe.

Ce que vous obtenez

  • Trois modèles d’accès : sans abonnement, inclus + payant, ou payant uniquement
  • Stripe Checkout hébergé — les utilisateurs passent à la version payante sans que vos données de carte ne transitent par votre code
  • Portail client — les utilisateurs mettent à jour leurs méthodes de paiement, téléchargent des factures, annulent — tout sur l’interface de Stripe
  • Cycle de vie piloté par webhooks — les abonnements se provisionnent et se renouvellent automatiquement ; les utilisateurs payants annulés reviennent au niveau inclus (ou deviennent non autorisés en mode payant uniquement) à la fin de la période
  • Application des quotas — utilisation des tokens suivie par période ; interruption en cours de flux avec une invite de mise à niveau structurée
  • Pages d’administration pour la gestion des plans et la surveillance des abonnements

Prérequis

  1. Compte Stripe avec le mode Live activé. Les entreprises constituées à Singapour doivent compléter la vérification KYC (UEN commercial, ID du directeur, compte bancaire). L’approbation prend généralement 1 à 3 jours.
  2. Clé API Stripe Live de type Restricted (recommandée plutôt que Standard sk_live_*** — plus facile à révoquer, permissions limitées).
  3. Point de terminaison webhook accessible publiquement à <your-domain>/api/webhooks/stripe.
  4. Compte bancaire pour les versements. Le règlement multi-devises (par ex. versement en USD vers un compte USD) est recommandé pour les comptes Stripe non-USD par défaut afin d’éviter une fuite de change de 1,5 à 2 % par transaction.

Configuration

1. Tableau de bord Stripe

Créer le produit Pro

  1. Catalog → Products → + Add product
  2. Name: Pro, description: 5M tokens / month, priority support
  3. Pricing: Recurring, monthly, $20.00 USD (adjust to your pricing strategy)
  4. Save → copy the resulting price_*** ID (you will UPDATE the local billing_plans table with this value after activation)

Créer une clé API restreinte

  1. Developers → API keys → + Create restricted key
  2. Name: fim-one production
  3. Permissions (minimum):
    • Customers: Write
    • Subscriptions: Write
    • Checkout Sessions: Write
    • Customer portal: Write
    • Prices: Read
    • Products: Read
  4. Save → copy rk_live_***

Enregistrer le point de terminaison du webhook

  1. Developers → Webhooks → + Add endpoint
  2. URL: https://<your-domain>/api/webhooks/stripe
  3. Événements à recevoir:
    • checkout.session.completed
    • customer.subscription.created
    • customer.subscription.updated
    • customer.subscription.deleted
    • invoice.payment_succeeded
    • invoice.payment_failed
  4. Après l’enregistrement, cliquez sur “Reveal signing secret” → copiez whsec_***

Configurer le règlement multi-devises (recommandé)

Si la devise par défaut de votre compte Stripe diffère de la devise de prix que vous facturez (cas courant : compte SGD facturant en USD) :
  1. Paramètres → Comptes bancaires et devises → Ajouter une devise de règlement
  2. Sélectionnez la devise de prix (par ex. USD)
  3. Attachez le compte bancaire correspondant (par ex. un compte virtuel Aspire USD)
  4. Enregistrez — Stripe achemine les frais USD directement vers les versements USD, sans conversion de change

2. Backend .env

Définissez ces trois clés dans votre .env de production :
Consultez Variables d’environnement pour la référence complète. Redémarrez le backend après avoir modifié .env pour que les clés soient prises en compte :

3. Activer dans Admin

  1. Connectez-vous en tant qu’administrateur
  2. Admin → System Settings → Access and billing
  3. Choisissez une posture (l’instance est toujours dans exactement une) :
    • No subscriptions (logiciel par défaut) — Stripe inutilisé. L’accès par token est le quota mensuel par défaut (0 = illimité).
    • Included + paid — Stripe requis. Les nouveaux utilisateurs arrivent sur le tier inclus ; ils peuvent passer à une version payante. Les utilisateurs payants annulés reviennent au tier inclus à la fin de la période.
    • Paid only — Stripe requis. Pas de tier inclus. Les utilisateurs doivent s’abonner avant de pouvoir appeler les modèles. Les utilisateurs du tier inclus existants conservent leur quota si vous passez de Included + paid.
  4. Le backend valide que STRIPE_SECRET_KEY et STRIPE_WEBHOOK_SECRET sont présents lorsque vous choisissez une posture Stripe — si l’un des deux est manquant, il retourne 400
  5. À la première activation d’une posture Stripe, le backend exécute une configuration idempotente :
    • Included + paid : initialise le plan inclus (slug=free) + un modèle Pro avec un ID de prix vide ; définit default_plan_id ; remplit rétroactivement les utilisateurs sans plan
    • Paid only : initialise uniquement le modèle Pro ; ne remplit pas rétroactivement
    • Copie default_token_quota sur le plan inclus lors de son initialisation (0 reste 0, illimité)
  6. Revenir à No subscriptions est un simple changement de drapeau sans effets secondaires sur les données. Le plan par défaut inclus ne peut pas être supprimé tant que Included + paid est actif.

4. Mettez à jour le plan Pro avec votre prix en direct

Après l’activation, mettez à jour le plan Pro pré-configuré pour pointer vers votre prix Stripe en direct :
  • Admin → Billing → Plans → Pro → Edit
  • Collez votre price_1*** (de l’étape 1) dans Stripe Price ID
  • Enregistrez
Ou via SQL (si vous préférez un accès direct à la base de données) :

5. Test de fumée

  1. Ouvrez /settings?tab=billing en tant qu’utilisateur ordinaire
  2. Cliquez sur Switch to Pro
  3. Stripe Checkout s’ouvre ; complétez avec une vraie carte à faible montant (remboursement après)
  4. Le webhook doit se déclencher — vérifiez dans Stripe Dashboard → Webhooks → les événements récents affichent des réponses 2xx
  5. Une ligne d’abonnement apparaît dans la table subscriptions ; users.plan_id bascule à pro
  6. L’interface affiche maintenant le plan Pro + le bouton « Manage subscription »

Désactiver la facturation

Basculez le commutateur Enable Stripe Billing sur OFF dans Admin → System Settings → Billing. Lorsque désactivé :
  • Tous les points de terminaison /api/billing/* retournent 503
  • Le point de terminaison webhook retourne 503 (Stripe réessaiera, puis s’affichera dans Dashboard comme défaillant — c’est normal, vous pouvez désactiver le webhook dans Stripe Dashboard à la place si la facturation est définitivement désactivée)
  • L’onglet Plan & Billing destiné aux utilisateurs disparaît
  • Le groupe de navigation Admin → Billing est masqué
  • La chaîne de quota ignore le niveau de plan et revient directement à default_token_quota
Les données sont préservées : les lignes subscriptions, billing_plans et users.plan_id existantes restent inchangées. La réactivation reprend à partir du même état sans migration.

Référence de calcul — mathématiques des quotas et des jetons

Ceci est la référence faisant autorité pour chaque règle numérique qui décide ce qu’un utilisateur est autorisé à consommer, quand son compteur se réinitialise, et comment la chaîne de résolution se compose. Lisez ceci avant de modifier la tarification, d’ajuster les quotas, de créer des tableaux de bord d’utilisation, ou de planifier les travaux v2/v3. Les règles futures non encore déployées sont documentées dans leur emplacement réservé afin que les contributeurs sachent où s’intègre la nouvelle logique.

Glossaire

Ce qui compte comme un token

La consommation de tokens est comptabilisée au niveau de l’appel LLM, provenant de l’objet usage de LiteLLM sur chaque completion.
  • Comptabilisé : tokens de prompt + tokens de completion sur chaque appel de modèle
  • Comptabilisé : chaque aller-retour dans un flux d’agent multi-étapes / tool-use (chaque appel de modèle est son propre débit)
  • Comptabilisé : demandes d’embedding (ingestion KB, scoring de récupération)
  • Non comptabilisé : entrée préparée mais jamais envoyée à un modèle (par exemple, fichiers téléchargés que l’utilisateur abandonne)
  • Non comptabilisé : demandes qui échouent avant d’atteindre le fournisseur (erreur d’authentification, pré-vérification de limite de débit)
  • Entrée en cache : comptabilisée au prix complet en v1 (aucune remise de cache du fournisseur n’est affichée). v2 peut créditer les tokens de prompt en cache séparément.

Sémantique de remplacement à trois états

users.token_quota est le remplacement administratif par utilisateur. Il porte trois significations dans une seule colonne : Le remplacement l’emporte toujours sur le plan et le défaut. Il existe pour permettre aux administrateurs d’épingler des utilisateurs individuels au-dessus ou au-dessous de leur niveau de plan sans toucher à Stripe.

Chaîne de résolution des quotas — v1 (actuelle)

Pour toute demande authentifiée, le plafond est calculé de haut en bas — la première correspondance gagne :
L’étape 4 est le plafond au niveau de l’instance pour Aucun abonnement. Sous Payant uniquement, un utilisateur sans plan n’a pas de droits (le chat retourne 402) même si default_token_quota est 0.

Réinitialisation de la période

  • Pour les utilisateurs payants, quota_reset_at reflète Subscription.current_period_end. Le gestionnaire webhook invoice.payment_succeeded définit tokens_used_this_period = 0 et avance quota_reset_at à la fin de la nouvelle période à chaque renouvellement réussi.
  • Pour les utilisateurs Free (sans abonnement Stripe), un cron horaire réinitialise tokens_used_this_period à 0 à la limite d’un mois calendaire ancrée à la date d’attribution du plan.
  • Les changements de plan en cours de période ne réinitialisent pas le compteur — seuls les renouvellements le font. Cela prévient les exploits de recyclage de quota (« s’abonner → utiliser le quota Pro → annuler → s’abonner à nouveau »).

Application de la limite en cours de flux

  • Vérification préalable à l’entrée de l’appel de chat : chemin le moins coûteux, bloque les demandes que l’utilisateur ne peut pas se permettre de démarrer.
  • Pendant le streaming, le nombre de tokens en cours est réévalué à chaque chunk. Le dépassement du plafond ferme le flux avec un cadre terminateur structuré, et non une erreur réseau.
  • Le frontend interprète le terminateur et affiche <QuotaExceededDialog> avec un lien profond vers /settings?tab=billing.
  • Les réponses non-streaming retournent HTTP 402 avec le corps { code: "QUOTA_EXCEEDED", reset_at, upgrade_url }.

Fallback avec facturation désactivée

Quand system_settings.billing_enabled = FALSE :
  • L’étape 2 de la chaîne est ignorée — la chaîne se réduit à override → default → unlimited.
  • /api/billing/* et /api/webhooks/stripe retournent 503.
  • L’onglet utilisateur Plan & Billing et le groupe de navigation Admin → Billing sont masqués.
  • Toutes les données de facturation (abonnements, plans, users.plan_id) sont conservées — la réactivation reprend à partir du même état sans migration.

Réservé : chaîne de quota v2 — Sièges d’équipe

Pas encore livré. Documenté ici pour que le travail v2 ait un point de destination connu.
Quand le plan Team sera lancé :
  • Subscription.quantity porte le nombre de sièges (natif Stripe).
  • Le plan effectif d’un utilisateur se résout via l’appartenance à l’équipe avant de revenir à son plan personnel :
  • Le quota est par siège (chaque membre de l’équipe obtient un monthly_token_quota complet), et non un pool partagé. Les pools partagés créent un épuisement au premier arrivé, premier servi et sont contraires aux intérêts des clients.
  • La sémantique des remplacements reste inchangée — les administrateurs d’équipe peuvent toujours plafonner fortement les membres individuels via users.token_quota = N, qui se situe au-dessus du plan d’équipe dans la chaîne.

Réservé : chaîne de quota v3 — allocation native Org (sans Stripe)

Pas encore livré. Réservé pour les déploiements sur site / entreprise qui allouent le quota en interne sans payer Stripe par utilisateur.
  • Nouvelle table org_quota_allocations(user_id, monthly_token_quota, org_id) distribue un budget parent entre les membres.
  • Les allocations sont par utilisateur, pas un pool partagé — chaque membre a un SLA individuel clair.
  • Chaîne mise à jour :
  • max(), pas sum(). Un utilisateur Pro payant n’obtient jamais moins que ce qu’il a payé, même si son administrateur Org définit une allocation basse. Le quota payé via Stripe est sacrosaint.

Réservé : solde de crédits à l’usage (dimension v3 séparée)

Pas encore livré. Un axe distinct de la chaîne ci-dessus — les crédits sont un rechargement unique, pas un niveau d’abonnement.
  • Nouvelle table user_credits(user_id, balance_cents, currency) — financée via Stripe Checkout mode='payment'.
  • Ordre de consommation : quota d’abonnement en premier, puis solde de crédits (la décrémentation des crédits ne commence qu’après l’épuisement de l’abonnement).
  • Le solde de crédits n’est pas remboursable (standard industriel pour les prépayés).
  • L’interface expose les deux barres : Quota d'abonnement : 4,2M / 5M utilisés + Crédits : 7,40 $ restants.

Valeurs par défaut

Valeurs par défaut au moment du déploiement — toutes modifiables après installation sauf indication contraire.

Modèle de tarification

V1 est un abonnement forfaitaire. Gratuit + Pro, facturation mensuelle, USD uniquement. Hors du champ d’application pour v1 (intentionnel, reporté à la feuille de route) :
  • Plan d’équipe (sièges Stripe / subscription.quantity)
  • Facturation annuelle
  • Présentation multi-devises
  • Coupons / codes promotionnels
  • Gestion des taxes (intégration Stripe Tax — nécessite un examen de conformité distinct)
  • Mesure basée sur l’utilisation / frais de dépassement
  • Solde de crédit à l’usage (recharge unique)
Consultez la feuille de route pour connaître les prochaines étapes prévues.

Dépannage

Le point de terminaison d’activation nécessite que STRIPE_SECRET_KEY et STRIPE_WEBHOOK_SECRET soient définis. Confirmez qu’ils sont présents dans .env et que le backend a été redémarré après la modification.
Soit la facturation est désactivée (le bouton bascule est OFF), soit la vérification de la signature de la requête a échoué (clé STRIPE_WEBHOOK_SECRET non concordante). Consultez Stripe Dashboard → Webhooks → événements récents pour voir le corps d’erreur réel.
Le webhook checkout.session.completed n’a pas atteint votre backend. Vérifiez que l’URL du point de terminaison dans Stripe Dashboard correspond exactement à <your-domain>/api/webhooks/stripe, y compris le chemin de fin. Consultez les livraisons récentes du webhook pour les défaillances.
La migration de seed écrit un ID de prix en mode test. Après l’activation de la facturation en production, mettez à jour le plan Pro pour utiliser votre price_1*** en direct via Admin → Billing → Plans → Pro → Edit, ou via une UPDATE SQL directe.
Configurez votre image de marque commerciale dans Stripe Dashboard → Settings → Branding. Ajoutez votre logo, le nom de votre entreprise (par exemple « FIM Labs Pte. Ltd. ») et votre adresse. Stripe applique ces paramètres à tous les reçus et factures générés automatiquement.
Si la devise par défaut de votre compte Stripe diffère de votre devise de facturation, Stripe convertit à chaque versement (écart de 1,5-2 %). Ajoutez une devise de règlement correspondante sous Settings → Bank accounts and currencies, attachez un compte bancaire dans la même devise, et Stripe acheminera les paiements dans la même devise sans conversion.