Fleeexdocs

Erreurs

Les erreurs typées que lève le SDK, les trois 402 différents, et tous les statuts et codes que renvoie l'API.

Le SDK lève trois sortes d'erreurs.

PaymentRequiredError

Levée quand le proxy ou getBalance() répond 402. Porte le lien de rechargement, quand il y en a un.

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);
    else showSupportMessage(); // pas de lien, voir plus bas
  }
}
PropriétéTypeNotes
status402Toujours 402.
codestring | undefinedLequel des trois 402 il s'agit.
topupUrlstring | undefinedLien signé et de courte durée pour faire passer l'utilisateur final par le Checkout. Réellement optionnel : vérifiez-le toujours avant de rediriger.
correlationIdstring | undefinedIdentifiant de trace pour le support et le débogage.
messagestringGénérique par conception, et ne révèle jamais l'existence d'un portefeuille.

Le hook onPaymentRequired (voir les options) se déclenche sur la même condition, avant que l'erreur ne soit levée.

Les trois 402

Le 402 ne recouvre pas une seule situation. Le code dit laquelle, et les trois appellent des remèdes différents. Faire un branchement dessus, c'est la différence entre dire à un utilisateur d'ajouter des fonds et lui annoncer une chose que payer ne réglera pas.

CodeSignificationtopupUrlQue faire
PAYMENT_REQUIREDLe couple (app, utilisateur) n'a pas de portefeuille autorisé, ou le solde ne couvre pas l'appel.toujoursEnvoyez l'utilisateur final vers topupUrl pour autoriser ou approvisionner.
APP_SPEND_CAP_EXCEEDEDVotre application a atteint le plafond mensuel de dépense que l'utilisateur lui a fixé, et son portefeuille peut être encore plein.le plus souventDites-lui que cette application a atteint le plafond que vous avez fixé, qu'il peut relever, plutôt que « ajoutez des fonds ». Le plafond est vérifié une fois en amont puis revérifié à l'écriture de la facturation ; la seconde vérification perd rarement une course, et lève alors le même code sans lien.
WALLET_SUSPENDEDLe portefeuille est bloqué après une sortie d'argent (un remboursement ou une opposition que le solde ne pouvait pas couvrir).jamaisArrêtez de réessayer et orientez l'utilisateur final vers le support. Approvisionner le portefeuille ne lève pas le blocage.

Traitez donc topupUrl comme optionnel sur n'importe quel 402, quel que soit le code, car deux des trois peuvent arriver sans.

Les deux premiers sont délibérément indiscernables l'un de l'autre dans le message : « pas de portefeuille » et « portefeuille vide » renvoient un corps identique, car les distinguer révélerait si un utilisateur donné possède un portefeuille Fleeex. Un utilisateur qui a révoqué votre application est indiscernable d'un utilisateur qui ne l'a jamais autorisée, pour la même raison.

WALLET_SUSPENDED ne porte ni montant, ni manque à couvrir, ni formulation de litige. Votre application n'y est pas partie, et l'historique de paiement de l'utilisateur final ne la regarde pas.

FleeexApiError

Tout autre code non 2xx renvoyé par une aide de facturation Fleeex (getConnection(), getUsageSummary(), ou un code autre que 402 sur getBalance()), par exemple un 400 quand un redirectUri n'est pas dans la liste autorisée de l'application.

PropriétéTypeNotes
statusnumberStatut HTTP.
codestring | undefinedCode d'erreur issu de l'enveloppe.
correlationIdstring | undefinedIdentifiant de trace.

Erreurs OpenAI

Sur le chemin du proxy, toute erreur autre qu'un 402 est levée par le SDK OpenAI sous forme d'OpenAI.APIError (et de ses sous-classes). Traitez-les exactement comme vous le feriez avec le SDK OpenAI, mais lisez le code, car plusieurs sont propres à Fleeex et ont des significations distinctes.

import OpenAI from "openai";
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);
  } else if (err instanceof OpenAI.APIError) {
    console.error(err.status, err.code, err.message);
  } else {
    throw err;
  }
}

Tous les statuts et codes

Toute la surface du plan de données : appels relayés, GET /v1/models et les aides de facturation.

StatutCodeQuand
400BAD_REQUESTUn model non pris en charge ou désactivé (le message renvoie en écho ce que vous avez envoyé, pas la cible d'un alias). Un paramètre non pris en charge, nommé, avec la liste des paramètres acceptés. Un corps malformé, ou imbriqué sur plus de 32 niveaux. Un x-fleeex-user absent ou malformé. Un redirectUri hors de la liste autorisée de l'application.
401UNAUTHORIZEDLa clé d'API est absente, invalide ou révoquée.
402PAYMENT_REQUIREDPas de portefeuille autorisé, ou solde insuffisant. Porte toujours topupUrl.
402APP_SPEND_CAP_EXCEEDEDLe plafond mensuel par application. Porte le plus souvent topupUrl, voir plus haut.
402WALLET_SUSPENDEDLe portefeuille est bloqué après une reprise de fonds. Ne porte jamais topupUrl.
403APP_SUSPENDEDVotre application a été suspendue par un opérateur Fleeex. Délibérément pas un 401 : l'identifiant est valide et nomme correctement votre application, donc faire tourner une clé ou réessayer ne change rien. Cessez d'appeler. Un flux en cours n'est pas coupé, mais la requête suivante est refusée.
403MODEL_NOT_ENTITLEDLe modèle existe mais il est réservé à d'autres applications, voir Choisir un modèle. L'appel n'atteint aucun fournisseur et ne réserve rien, et GET /v1/models l'omet purement et simplement : un appelant qui liste d'abord ne rencontre donc jamais ce cas.
404NOT_FOUNDGET /v1/models/{model} quand aucun modèle ni alias de ce nom n'est servi.
413PAYLOAD_TOO_LARGELe corps de la requête dépasse 1 Mo.
429TOO_MANY_REQUESTSLa limite de débit de Fleeex par application. Elle compte au niveau de votre application : toutes ses clés, y compris une clé de bac à sable, partagent une seule limite.
429CONCURRENT_STREAM_LIMITCet utilisateur final a déjà le nombre maximal de flux ouverts. Envoyé avec un en-tête Retry-After, et refusé avant toute réservation et tout appel au fournisseur : il ne coûte donc rien. Réessayez quand l'un des flux de cet utilisateur se termine ; le remède est de réduire le nombre de flux ouverts, pas la cadence des requêtes.
429UPSTREAM_THROTTLEDLe fournisseur de modèle a bridé l'appel. Réessayable, contrairement à UPSTREAM_PROVIDER_ERROR.
502UPSTREAM_PROVIDER_ERRORLe fournisseur a rejeté l'appel (accès au modèle, invocation non prise en charge, schéma hors de son sous-ensemble, dépassement de délai, panne). La réservation est libérée et rien n'est facturé.
500INTERNAL_SERVER_ERRORUne faute de Fleeex. Le détail est journalisé côté serveur en regard du correlationId ; la réponse n'en dit pas plus.

Un appel refusé ne coûte rien : un 400, un 402, un 403 ou la limite de flux court-circuitent avant d'atteindre le fournisseur, si bien qu'aucune complétion n'est jamais générée puis jetée.

Enveloppe des erreurs

Le backend de Fleeex émet un corps cohérent, exposé sous le type FleeexErrorBody.

interface FleeexErrorBody {
  error?: { code?: string; message?: string; correlationId?: string };
  topupUrl?: string;
}

correlationId est la seule chose qui mérite d'être journalisée de votre côté : c'est la prise qui relie votre appel en échec à sa trace côté serveur. Il est renvoyé en écho sur chaque réponse, et pas seulement sur les erreurs, et vous pouvez fournir le vôtre via un en-tête de requête x-correlation-id.

Un message n'est jamais une trace de pile, une erreur de SDK cloud ou un identifiant interne, et pour un 500, jamais rien d'autre que le texte générique ci-dessus.