Passer au contenu principal

Documentation Index

Fetch the complete documentation index at: https://docs.fim.ai/llms.txt

Use this file to discover all available pages before exploring further.

FIM One intègre un pipeline de facturation Stripe complet contrôlé par un drapeau de fonctionnalité administrateur. Les déploiements privés sans besoin de paiement le laissent désactivé et ne voient jamais l’interface utilisateur. Les opérateurs SaaS basculent un seul paramètre et obtiennent immédiatement la Checkout hébergée, le Portail Client, le cycle de vie des abonnements piloté par webhook et l’application des quotas.
La facturation est désactivée par défaut. Les nouvelles installations et les déploiements autonomes existants commencent avec system_settings.billing_enabled = FALSE. Aucune interface de facturation n’apparaît tant qu’un administrateur ne l’active pas explicitement.

Ce que vous obtenez

  • Niveaux Free + Pro avec quotas de tokens mensuels (par défaut : Free 1M / Pro 5M ; tous deux ajustables après activation)
  • Stripe Checkout hébergé — les utilisateurs passent à la version payante sans que votre code ne touche jamais aux données de carte
  • Portail client — les utilisateurs mettent à jour les méthodes de paiement, téléchargent les factures, annulent — tout sur l’interface de Stripe
  • Cycle de vie piloté par webhooks — les abonnements se provisionnent et se renouvellent automatiquement ; les abonnements annulés rétrogradent à Free à la fin de la période
  • Application des quotas — utilisation des tokens suivie par période ; arrêt 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 :
STRIPE_SECRET_KEY=rk_live_***
STRIPE_WEBHOOK_SECRET=whsec_***
STRIPE_BILLING_RETURN_URL=https://<your-domain>/settings?tab=billing
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 :
./deploy.sh   # or: docker compose restart fim-one

3. Activate in Admin

  1. Log in as an admin
  2. Admin → System Settings → Billing
  3. Toggle Enable Stripe Billing ON
  4. The backend validates that both STRIPE_SECRET_KEY and STRIPE_WEBHOOK_SECRET are present — if either is missing it returns 400 and the toggle stays OFF
  5. On first activation only, the backend runs an idempotent setup:
    • Seeds Free + Pro plans (skipped if already present)
    • Sets system_settings.default_plan_id to the Free plan id
    • Backfills users.plan_id = free.id for any user without a plan
    • Syncs default_token_quota → Free plan monthly_token_quota so the existing admin-controlled global quota carries over
  6. Subsequent toggle off/on is a pure flag flip with no data side effects

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) :
UPDATE billing_plans
SET stripe_price_id = 'price_1***'
WHERE slug = 'pro';

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

VariableStockageSémantiquePlage
users.token_quotapar utilisateur (remplacement)Remplacement à trois états ; voir la sémantique ci-dessousNULL, 0, ou entier positif
users.tokens_used_this_periodpar utilisateur (compteur)Tokens cumulatifs depuis la dernière réinitialisationentier non-négatif
users.quota_reset_atpar utilisateur (ancre)Reflète Subscription.current_period_end pour les utilisateurs payantstimestamp
users.plan_idpar utilisateur (FK)Plan actifFK billing_plans.id
billing_plans.monthly_token_quotapar planLimite maximale pour les utilisateurs de ce planentier non-négatif
system_settings.default_token_quotasingletonSecours défensif quand aucun plan ne s’appliqueentier non-négatif
system_settings.default_plan_idsingletonPointeur de plan gratuit pour les utilisateurs nouveaux/non assignésFK ou NULL
system_settings.billing_enabledsingletonCommutateur maître — contrôle l’étape 2 de la chaînebooléen

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 :
ValeurSignificationCas d’usage
NULLNon défini — déférer au plan / défautÉtat par défaut pour tous les utilisateurs normaux
0IllimitéComptes administrateur / internes ; « cadeau VIP »
N > 0Limite stricte à NBloquer un contrevenant sans annuler son abonnement payant ; allocation d’entreprise prépayée
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 requête authentifiée, le plafond est calculé de haut en bas — la première correspondance gagne :
1. users.token_quota        ── NULL? skip. 0? unlimited. N>0? cap at N.
2. users.plan.monthly_token_quota   ── only when billing_enabled = TRUE
3. system_settings.default_token_quota  ── defensive fallback
4. unlimited                ── last resort if everything above is NULL
L’étape 3 est rarement atteinte quand la facturation est activée, car l’activation remplit rétroactivement users.plan_id pour chaque utilisateur. Elle existe comme une défense en profondeur pour qu’un plan mal configuré ne lève jamais silencieusement le plafond d’un utilisateur.

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 :
    effective_plan = team.plan if team_member(user) else user.plan
    
  • 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 :
    override → max(plan_quota, org_allocation) → default → unlimited
    
  • 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 ajustables après installation sauf indication contraire.
VariableDéfautAjustable via
billing_plans.monthly_token_quota (Free)1,000,000Admin → Billing → Plans → Free → Edit
billing_plans.monthly_token_quota (Pro)5,000,000Admin → Billing → Plans → Pro → Edit
system_settings.default_token_quota1,000,000 (synchronisé avec Free à l’activation)Admin → System Settings → Quotas
system_settings.billing_enabledFALSEAdmin → System Settings → Billing
Prix catalogue Pro$20.00 USD / moisStripe Dashboard (objet price)
Événements webhook Stripe abonnés6Stripe Dashboard → Webhooks
TTL cache prix Stripe5 minutescodé en dur dans stripe_client.py
Cron cycle de vie abonnementtoutes les heuresAPScheduler dans web/main.py
Cron réinitialisation niveau gratuittoutes les heures (limite calendaire mensuelle)APScheduler dans web/main.py

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.