Fleeexdocs

Solde et paiements

Lisez le solde du portefeuille et gérez le 402 Payment Required avec son lien de rechargement signé.

Fleeex est prépayé : deux choses comptent donc pour une intégration, connaître le solde, et gérer proprement le moment où il s'épuise.

Lire le solde

const { balanceMicros, currency } = await client.getBalance();
// balanceMicros est en micro-unités EUR : 1_000_000 = 1,00 €

getBalance() renvoie un BalanceResponse. Les montants sont en micro-unités pour éviter les dérives de virgule flottante : divisez par 1 000 000 pour obtenir l'unité principale.

const eur = balanceMicros / 1_000_000; // ex. 4_250_000 → 4,25

Comme un appel relayé, getBalance() lève PaymentRequiredError si le couple (app, utilisateur) n'a pas de portefeuille approvisionné et autorisé.

Les montants sont hors taxes

Le portefeuille contient des crédits hors taxes : la TVA est calculée et encaissée en sus au moment du Checkout, et le solde est crédité du montant hors taxes. Un utilisateur qui a payé 12,00 € voit donc un solde inférieur, et la différence n'est pas de l'argent disparu. Si vous affichez ce chiffre, présentez-le comme du crédit IA plutôt que comme un montant payé. Ses reçus, eux, vivent dans son compte Fleeex.

C'est le solde du portefeuille, pas celui de votre application

Un seul solde finance toutes les applications que l'utilisateur a connectées : balanceMicros peut donc bouger sans que votre application n'y soit pour rien. Ce qui borne la part de votre application, c'est le plafond mensuel que l'utilisateur lui fixe, et c'est pourquoi l'atteindre a son propre code 402, ci-dessous.

Gérer le 402 Payment Required

Quand le portefeuille n'est pas approvisionné ou pas autorisé, le proxy comme getBalance() lèvent une PaymentRequiredError typée, porteuse le plus souvent d'un lien de rechargement signé et de courte durée. Envoyez-y l'utilisateur final pour approvisionner le portefeuille :

import { PaymentRequiredError } from "@fleeex/sdk";
 
try {
  await client.chat.completions.create({ model, messages });
} catch (err) {
  if (err instanceof PaymentRequiredError) {
    if (err.topupUrl) redirect(err.topupUrl); // envoyer l'utilisateur vers le Checkout
    else showSupportMessage(); // un portefeuille suspendu n'a pas de lien, voir plus bas
  } else {
    throw err;
  }
}

PaymentRequiredError expose topupUrl, code, correlationId et status (toujours 402). Le message est volontairement générique, car Fleeex ne révèle jamais l'existence d'un portefeuille : les parties exploitables sont donc code et topupUrl.

Le 402 recouvre trois situations différentes

Faites vos branchements sur code. Envoyer quelqu'un au Checkout quand payer ne peut pas l'aider est pire que de ne rien dire :

codeSignificationtopupUrl
PAYMENT_REQUIREDPas de portefeuille autorisé, ou solde insuffisant.toujours
APP_SPEND_CAP_EXCEEDEDVotre application a atteint le plafond mensuel que l'utilisateur lui a fixé. Son portefeuille peut être encore plein : le message à afficher est « relevez le plafond », pas « ajoutez des fonds ».le plus souvent
WALLET_SUSPENDEDLe portefeuille est bloqué après qu'un remboursement ou une opposition a repris l'argent. L'approvisionner ne lève pas le blocage : orientez l'utilisateur vers le support.jamais
switch (err.code) {
  case "WALLET_SUSPENDED":
    return showSupportMessage();
  case "APP_SPEND_CAP_EXCEEDED":
    return showCapReached(err.topupUrl); // peut être undefined
  default:
    return err.topupUrl ? redirect(err.topupUrl) : showGenericMessage();
}

topupUrl est optionnel sur n'importe quel 402 : ne le déréférencez jamais sans vérification. Un refus lié au plafond de dépense qui perd la course avec l'écriture de la facturation arrive sans lien.

Voir la référence des erreurs pour le contrat complet, et le Bac à sable pour reproduire les trois cas à la demande plutôt que de les attendre en production.

Le gérer en un seul endroit

Répéter ce try/catch partout est fastidieux. Enregistrez une fois le hook onPaymentRequired : il se déclenche chaque fois qu'un 402 est traduit (depuis un appel relayé ou depuis getBalance()), juste avant que l'erreur ne soit levée.

const client = new FleeexClient({
  apiKey,
  userId,
  onPaymentRequired: (err) => {
    if (err.topupUrl) redirect(err.topupUrl);
  },
});

Le hook s'exécute d'abord ; l'appel échoue quand même avec la PaymentRequiredError, si bien que tout try/catch local continue de fonctionner.

L'argent est crédité sur le paiement vérifié, pas sur le retour

Le lien fait passer l'utilisateur final par un Checkout hébergé. Son solde est crédité quand le prestataire de paiement confirme l'opération, jamais quand il revient sur votre redirectUri : un getBalance() juste après le retour peut donc encore lire l'ancien chiffre. Ne conditionnez pas votre interface à la seule redirection : interrogez périodiquement, ou abonnez-vous à topup.completed pour être prévenu.

Éviter complètement le 402

Pour vérifier en amont, avant un premier appel de chat, qu'un utilisateur est connecté et approvisionné, utilisez getConnection(), qui renvoie l'état sans jamais lever de 402.