Skip to main content
Chaque erreur que l’API Samsa renvoie — pour n’importe quel endpoint, à n’importe quel statut — utilise une enveloppe JSON cohérente. Analyse le code lisible par machine, pas le message humain (les messages peuvent changer ; les codes sont stables).

L’enveloppe d’erreur

Les réponses réussies ne contiennent jamais d’objet error. Branche d’abord sur le statut HTTP, puis sur error.code.

Codes d’erreur


invalid_api_key

HTTP 401. Le header Authorization est manquant ou malformé, ou la clé est inconnue, expirée ou révoquée — ou le créateur de la clé n’est plus membre de l’organisation. Les clés expirées et inconnues sont intentionnellement indistinguables.
Comment gérer. Vérifie le header Authorization: Bearer samsa_sk_…. Si la clé a été révoquée ou a expiré, crées-en une nouvelle. Ne réessaie pas — le résultat ne changera pas.

missing_scope

HTTP 403. La clé est valide mais n’a pas le scope que le endpoint requiert. param vaut "scope" et le message nomme le scope manquant.
Comment gérer. Un admin modifie les scopes de la clé (ou émet une nouvelle clé) pour accorder le scope nommé. Ne réessaie pas sans changer la clé.

insufficient_credits

HTTP 402. Le pool de credits dépensable de l’organisation (abonnement plus top-ups valides) est en dessous du coût de l’action. Voir Tarification. Si l’organisation a au moins une équipe active, l’API renvoie à la place les codes liés aux équipes insufficient_team_credits ou insufficient_unallocated_credits — à deux exceptions près. Une organisation système exemptée du budgeting par équipe reste sous le régime org et garde ce code générique même avec des équipes actives. Et une défaillance opérationnelle dans la déduction elle-même (par exemple une lecture de solde dégradée) retombe sur ce code générique quel que soit le régime de budget. Un simple insufficient_credits dans une configuration avec équipes peut donc être transitoire ; réessaie avant de le traiter comme un solde épuisé.
Comment gérer. Si un GET /credits ultérieur montre un available couvrant le coût, tu as peut-être rencontré le repli opérationnel — réessaie une fois. Cette lecture n’est toutefois qu’un instantané : un changement d’état depuis le refus (un top-up, un remboursement, un budget modifié ou une réinitialisation de période) peut aussi l’expliquer, un vrai manque de solde n’est donc pas exclu. Sinon, recharge ou fais évoluer le plan de l’organisation dans l’app, puis réessaie. Rien n’a été facturé et aucun job n’a été créé.

subscription_inactive

HTTP 402. L’organisation n’a aucun abonnement utilisable (aucun actif, en période de grâce, ou détenant des top-ups dépensables). Distinct de insufficient_credits, où un abonnement existe mais le pool est trop bas.
Comment gérer. Réactive la facturation de l’organisation dans l’app, puis réessaie.

insufficient_team_credits

HTTP 402. Les organisations peuvent répartir leurs credits d’abonnement mensuels en budgets par équipe, et chaque clé API peut être assignée à une équipe. Une clé assignée à une équipe avec budget dépense depuis le bucket mensuel de cette équipe ; tout ce qui n’est alloué à aucun budget d’équipe forme le pool non alloué de l’organisation. Les top-ups achetés sont exemptés des budgets et restent disponibles pour couvrir le reste. Ce code survient quand le solde que la clé peut dépenser — le plus petit du pool de plan restant de l’organisation et du budget restant de l’équipe, plus les top-ups — est en dessous du coût de l’action. C’est exactement l’available rapporté par GET /credits.
Le code nomme le régime de budget, pas le solde qui s’est épuisé. Une clé assignée à une équipe budgétée reçoit ce code même quand c’est le pool de plan de l’organisation, et non le budget d’équipe, qui était épuisé — l’équipe peut donc encore afficher de la marge. Compare plan_credits à scope.remaining sur GET /credits pour voir lequel contraint.
Comment gérer. Un admin de l’organisation peut augmenter le budget mensuel de l’équipe, assigner la clé à une autre équipe, ou acheter des top-ups (les top-ups ne sont pas limités par les budgets d’équipe). L’utilisation du budget se réinitialise aussi à la prochaine période de facturation. Rien n’a été facturé et aucun job n’a été créé.

insufficient_unallocated_credits

HTTP 402. La clé n’est pas assignée à une équipe avec budget (non assignée, ou son équipe n’a pas de budget), elle dépense donc depuis le pool non alloué de l’organisation — les credits d’abonnement mensuels restants après soustraction des budgets de toutes les équipes actives. Ce code survient quand le solde que la clé peut dépenser — le plus petit du pool de plan restant de l’organisation et de la marge de ce pool non alloué, plus les top-ups exemptés des budgets — est en dessous du coût de l’action, avec la même réserve que ci-dessus sur le solde réellement épuisé. Les organisations sans équipe active ne voient jamais les deux codes liés aux équipes — elles reçoivent le simple insufficient_credits à la place.
Anticipe-le. GET /credits rapporte available — ce que la clé appelante peut dépenser maintenant — et un bloc scope qui nomme son régime de budget. Un job dont les estimated_credits tiennent dans available n’est refusé par aucun de ces trois codes, tant que l’état des credits et des budgets/équipes ne change pas entre-temps — hormis le repli opérationnel : une déduction dégradée peut renvoyer le générique insufficient_credits même dans ce cas, donc réessaie d’abord.
Comment gérer. Un admin de l’organisation peut libérer des credits non alloués en baissant les budgets d’équipe, assigner la clé à une équipe avec du budget disponible, faire évoluer le plan, ou acheter des top-ups. Rien n’a été facturé et aucun job n’a été créé.

not_found

HTTP 404. L’id est inconnu, ou il appartient à une autre organisation. Les deux cas sont indistinguables par conception, donc l’existence n’est jamais divulguée entre organisations.
Comment gérer. Vérifie l’id, et que l’organisation de la clé possède bien la ressource. Ne réessaie pas.

validation_error

HTTP 422. Le corps de la requête ou un paramètre a échoué à la validation. param nomme le champ fautif ; message explique la contrainte.
Comment gérer. Corrige la requête selon message et param, puis renvoie-la. C’est une erreur client — réessayer la même requête échouera de façon identique.

svg_acceptance_required

HTTP 422. Seul POST /images/vectorizations renvoie ce code. Le SVG est une exclusion de périmètre documentée au titre de l’art. 50(2) du règlement européen sur l’IA : un SVG ne peut porter ni manifeste C2PA ni filigrane intégré, donc les sorties vectorielles sont livrées non signées. svg_acceptance doit donc être le booléen littéral true — une valeur absente, false ou autre est rejetée avec ce code distinct, jamais avec le validation_error générique. Cette reconnaissance est une divulgation / preuve d’audit, pas une renonciation à la conformité. Rien n’est facturé et aucun job n’est créé.
Comment le gérer. Renvoie la requête avec "svg_acceptance": true dès que ton intégration expose l’avertissement de sortie non signée à celles et ceux qui exploitent le résultat.

svg_phase1_scope_out_required

HTTP 403. Également réservé à la vectorisation, et distinct de missing_scope — le scope de la clé est correct. La livraison exige en plus une acceptation des ToS/AUP à jour, vérifiée côté serveur ; le flag svg_acceptance de la requête n’est jamais retenu comme cette preuve. À la soumission, une acceptation manquante ou périmée est refusée avant toute facturation. Le contrôle est rejoué à la livraison : un job déjà accepté peut donc encore être refusé par GET /images/vectorizations/{id} ou lors de l’émission du webhook si l’acceptation expire entre-temps — un refus à la livraison n’ajoute aucun frais, mais ne rembourse pas les crédits déjà consommés par le job terminé.
Comment le gérer. Accepte les ToS/AUP en vigueur dans l’app Samsa, puis réessaie. Pour un job refusé à la livraison, redemande son statut GET — le webhook n’est pas rejoué automatiquement. Accepter est une divulgation, pas une renonciation.

rate_limited

HTTP 429. La clé a dépassé sa fenêtre de rate de requêtes par clé. La réponse porte les headers Retry-After et X-RateLimit-*. Voir Rate limits.
Comment gérer. Ralentis et réessaie après l’intervalle Retry-After. Utilise un backoff exponentiel pour des 429 répétés.

too_many_active_jobs

HTTP 429. L’organisation a atteint son plafond de jobs concurrents en cours. Le message inclut le compte actuel et la limite, et un header Retry-After est défini.
Comment gérer. Attends que les jobs en cours atteignent un statut terminal (interroge leur endpoint GET ou utilise un webhook) avant d’en soumettre d’autres, puis réessaie après Retry-After.

internal_error

HTTP 500. Une erreur inattendue du côté de Samsa. La réponse ne divulgue jamais de détails internes — le request_id est ton point d’entrée pour le support.
Comment gérer. Réessaie avec un backoff — les 500 sont souvent transitoires. Si cela persiste, contacte support@samsa.ai avec le request_id.

Utiliser request_id pour le support

Chaque erreur (et chaque succès) porte un request_id, aussi renvoyé dans le header de réponse X-Request-ID. Il relie ton erreur côté client, le header de réponse et les logs serveur de Samsa à une même requête. Log-le, et cite-le quand tu contactes support@samsa.ai — c’est le moyen le plus rapide pour nous de retrouver exactement ce qui s’est passé.
De nouveaux codes d’erreur peuvent être ajoutés au fil du temps (par exemple des codes additifs par endpoint). Traite un code non reconnu comme sa classe de statut HTTP, et branche toujours sur code plutôt que sur une correspondance de texte de message.