Skip to content
ABUNA
DocumentationErreurs

Pour commencer

Erreurs

Codes de statut, codes d'erreur, erreurs de champ, limites de débit, identifiants de requête, et comment réessayer sans risque.

Une requête qui échoue renvoie un statut 4xx ou 5xx et un corps JSON. Le corps contient un code qui reste le même et une phrase error destinée aux développeurs. Branchez sur le statut et le code. N'analysez pas error, car sa formulation peut changer.

Corps d'erreur
{
  "code": "unauthenticated",
  "error": "missing or invalid API key"
}

Identifiants de requête

Chaque réponse, échouée ou non, a un en-tête X-Request-Id, comme req_01J9ZQB21C3D4E5F6G7H8J9K0M. Journalisez-le avec votre propre trace de la requête. Quand vous contactez le support au sujet d'une requête, citez son X-Request-Id.

Erreurs de champ

Quand une requête échoue à cause de son entrée, le corps contient aussi un tableau errors, avec un élément par champ. Une validation échouée renvoie 422 avec le code invalid et liste chaque champ qui a échoué.

Erreurs de champ (422)
{
  "code": "invalid",
  "error": "email is required; phone_number is required",
  "errors": [
    { "field": "email", "code": "invalid", "error": "email is required" },
    { "field": "phone_number", "code": "required", "error": "phone_number is required" }
  ]
}

Le code de chaque élément est l'un des suivants :

  • required : le champ est manquant ou vide.
  • invalid : la valeur n'est pas autorisée, comme un montant de 0 ou un statut inconnu.
  • currency_unsupported : la devise n'est pas XAF.
  • phone_invalid : le numéro de téléphone n'a pas d'indicatif pays, ou n'a pas le bon nombre de chiffres pour son pays.
  • phone_country_unsupported : votre prestataire de paiement ne peut pas débiter les numéros de ce pays dans la devise du tarif. Le paiement et l'espace client les refusent.
  • unchanged : la valeur est celle déjà définie, comme un nouveau montant de tarif égal au montant actuel.
  • too_soon : la date est trop proche, comme un changement de tarif à moins de 14 jours.
  • unknown_field : une mise à jour a envoyé un champ que l'endpoint n'accepte pas.
  • not_found : l'ID du champ n'existe pas dans l'application, comme un price_id ou un invoice_id quand vous créez une session.
  • url_invalid : l'URL n'est pas une URL absolue avec un hôte, ou utilise http là où seul https est autorisé.

Le slug d'un produit doit être unique dans son application. Un slug que vous envoyez et qu'un autre produit possède renvoie 409 avec le code slug_taken, et son élément errors nomme le champ slug. Un slug qu'Abuna construit à partir du nom n'entre jamais en conflit.

Codes d'erreur

Voici les codes qu'une requête avec une clé secrète peut recevoir. Chaque code indique le statut HTTP qui l'accompagne.

Codes d'erreur

  • invalid_json400

    Le corps n'est pas un JSON valide, contient une valeur du mauvais type, ou un champ que l'endpoint n'accepte pas.
  • invalid422

    Un ou plusieurs champs ont échoué à la validation. Voir errors pour chaque champ. Un en-tête Idempotency-Key de plus de 255 caractères reçoit ce code avec 400.
  • payment_declined402

    Le paiement a échoué. Le prestataire peut aussi donner une raison plus précise, listée plus bas.
  • insufficient_funds402

    Le solde du client est trop bas.
  • payment_not_approved402

    Le client a refusé la demande sur son téléphone ou l'a laissée expirer.
  • wallet_not_found402

    Le numéro n'a pas de portefeuille sur le réseau débité, ou n'est pas un numéro valide.
  • wallet_limit_reached402

    Le portefeuille du client a atteint une limite de transaction ou de solde.
  • wallet_busy402

    Un autre paiement attend déjà l'approbation du client.
  • network_unavailable402

    Le réseau ne peut pas prendre ce paiement maintenant, ou ne peut pas le prendre du tout avec votre compte prestataire.
  • unauthenticated401

    La requête n'a pas de clé, ou la clé est incorrecte ou révoquée. Vérifiez l'en-tête Authorization.
  • forbidden403

    Une clé secrète a appelé un endpoint qui exige une connexion au tableau de bord, ou une connexion au tableau de bord ou une clé publiable a appelé un endpoint qui exige une clé secrète, comme les sessions.
  • email_unverified403

    L'application est en mode Réel et le propriétaire d'équipe n'a pas vérifié son e-mail.
  • plan_limit403

    La requête dépasserait une limite de votre forfait, comme son nombre d'abonnés Réels.
  • plan_read_only403

    Votre forfait a rendu cette application Réelle en lecture seule. Les lectures fonctionnent toujours, tout comme le débit d'une facture.
  • not_found404

    L'objet nommé dans le chemin n'existe pas dans l'application. Un ID d'application qui n'existe pas, ou auquel votre clé n'appartient pas, reçoit aussi ce code.
  • plan_offer_not_found404

    Le lien de changement de formule est incorrect. Envoyez-en un nouveau au client avec Changer de formule.
  • slug_taken409

    Un autre produit de l'application a déjà le slug que vous avez envoyé. Envoyez un slug différent.
  • already_paid409

    La facture est déjà payée.
  • invoice_not_open409

    La facture est annulée (void), par exemple parce que l'abonnement a été résilié. Vous ne pouvez pas créer de session pour la payer.
  • subscription_canceled409

    L'abonnement a pris fin, donc une résiliation planifiée ne peut pas être annulée et vous ne pouvez pas demander de résiliation. Créez plutôt un nouvel abonnement.
  • subscription_not_active409

    Vous ne pouvez demander une résiliation que pour un abonnement active ou past_due. Un abonnement pending, dont la première période n'est pas encore payée, reçoit ce code.
  • cancel_already_scheduled409

    L'abonnement est déjà programmé pour être résilié, vous ne pouvez donc pas demander de résiliation.
  • payment_in_progress409

    Un paiement pour cette facture attend déjà une approbation. Un changement de formule ou une résiliation qui annulerait une période impayée, ou remplacerait une mise à niveau en attente de paiement, reçoit aussi ce code tant que ce paiement est en cours.
  • plan_change_unavailable409

    L'abonnement n'est ni active ni past_due, sa formule ne peut donc pas changer. Un abonnement dont la première période n'est pas encore payée ne peut pas changer de formule.
  • renewal_paid_early409

    Le client a déjà payé la période suivante avant qu'elle commence, donc une mise à niveau attend le début de cette période. Rien n'a été débité.
  • plan_offer_inactive409

    L'offre de changement de formule a déjà été acceptée, annulée ou remplacée par une plus récente.
  • session_not_open409

    La session est déjà terminée ou expirée, elle ne peut donc pas être expirée.
  • idempotency_in_progress409

    Une requête avec la même Idempotency-Key est toujours en cours. Réessayez dans un instant.
  • no_pending_change409

    Le tarif n'a aucun changement programmé à annuler.
  • change_in_effect409

    Le changement en attente du tarif a atteint son effective_at et prend effet, il ne peut donc pas être remplacé ni annulé. Cela dure de effective_at jusqu'à l'événement price_change.applied, généralement moins d'une minute. Ensuite, vous pouvez programmer un nouveau changement.
  • conflict409

    La requête entre en conflit avec l'état actuel de l'objet.
  • price_archived410

    Le tarif est archivé, aucun nouvel abonnement ne peut l'utiliser.
  • plan_offer_expired410

    L'offre de changement de formule a expiré. Elle dure 7 jours, ou jusqu'à la fin de la période en cours si elle survient avant.
  • session_expired410

    La session a expiré avant que le client ait soumis ses informations. La page de paiement hébergée reçoit ce code, pas votre serveur. Créez une nouvelle session.
  • price_not_eligible422

    L'abonnement ne peut pas passer à ce tarif : c'est le tarif actuel, il est archivé, il est pour un autre produit, dans une autre devise, ou n'est pas dans l'application.
  • not_accepting_payments422

    L'application Réelle ne peut pas encore encaisser de paiements : le propriétaire d'équipe n'a pas vérifié son e-mail, aucun prestataire de paiement n'est connecté, ou l'application n'a pas d'e-mail ni d'URL de support. Une mise à niveau avec quelque chose à payer reçoit aussi ce code.
  • payment_unavailable422

    La méthode de paiement n'est pas proposée, ou ne prend pas les paiements dans la devise de la facture.
  • idempotency_key_reused422

    L'Idempotency-Key a déjà été utilisée avec une requête différente au cours des dernières 24 heures. Utilisez une nouvelle clé pour une nouvelle requête.
  • webhook_url_missing422

    Vous avez demandé d'envoyer ou de renvoyer un webhook, mais l'application n'a pas d'URL de webhook.
  • rate_limited429

    Trop de requêtes. Voir Limites de débit.
  • internal500

    Quelque chose s'est mal passé du côté d'Abuna. Réessayez plus tard.

Limites de débit

  • Chaque adresse IP peut faire 600 requêtes par minute.
  • Chaque application peut envoyer 10 webhooks de test par minute.

Au-delà d'une limite, l'API renvoie 429 avec le code rate_limited et un en-tête Retry-After. Attendez ce nombre de secondes, puis réessayez.

Limite de débit atteinte (429)
{
  "code": "rate_limited",
  "error": "too many requests"
}

Requêtes idempotentes

Chaque POST accepte un en-tête Idempotency-Key, pour que vous puissiez réessayer une requête après une erreur réseau ou un 5xx sans refaire le travail. Envoyez une nouvelle valeur aléatoire, jusqu'à 255 caractères, pour chaque nouvelle requête, et la même valeur à chaque nouvelle tentative de celle-ci. Sans l'en-tête, chaque requête s'exécute.

POST /v1/apps/{appID}/sessions avec Idempotency-Key
curl https://api.abuna.app/v1/apps/8ddhXCDW/sessions \
  -H "Authorization: Bearer sk_test_..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 6f1c2b9e-4d3a-4c8e-9a7f-2e5b8d1c0a43" \
  -d '{
    "type": "checkout",
    "price_id": "Zt6YbN3q",
    "metadata": {"user_id": "42"}
  }'

Abuna conserve une clé pendant 24 heures, par application. Quand une requête réutilise une clé :

  • La même requête, vers le même chemin avec le même corps, reçoit à nouveau la première réponse, avec son statut et son corps, plus l'en-tête Idempotent-Replayed: true.
  • Une requête différente renvoie 422 avec le code idempotency_key_reused.
  • Tant que la première requête est en cours, elle renvoie 409 avec le code idempotency_in_progress. Réessayez dans un instant.
  • Si la première requête a reçu un 5xx, la clé n'est pas conservée, donc la nouvelle tentative s'exécute à nouveau.

Une clé de plus de 255 caractères renvoie 400 avec le code invalid.

Étapes suivantes