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.
{
"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é.
{
"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 de0ou un statut inconnu.currency_unsupported: la devise n'est pasXAF.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 unprice_idou uninvoice_idquand vous créez une session.url_invalid: l'URL n'est pas une URL absolue avec un hôte, ou utilisehttplà où seulhttpsest 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_json400Le corps n'est pas un JSON valide, contient une valeur du mauvais type, ou un champ que l'endpoint n'accepte pas.invalid422Un ou plusieurs champs ont échoué à la validation. Voirerrorspour chaque champ. Un en-têteIdempotency-Keyde plus de 255 caractères reçoit ce code avec400.payment_declined402Le paiement a échoué. Le prestataire peut aussi donner une raison plus précise, listée plus bas.insufficient_funds402Le solde du client est trop bas.payment_not_approved402Le client a refusé la demande sur son téléphone ou l'a laissée expirer.wallet_not_found402Le numéro n'a pas de portefeuille sur le réseau débité, ou n'est pas un numéro valide.wallet_limit_reached402Le portefeuille du client a atteint une limite de transaction ou de solde.wallet_busy402Un autre paiement attend déjà l'approbation du client.network_unavailable402Le réseau ne peut pas prendre ce paiement maintenant, ou ne peut pas le prendre du tout avec votre compte prestataire.unauthenticated401La requête n'a pas de clé, ou la clé est incorrecte ou révoquée. Vérifiez l'en-tête Authorization.forbidden403Une 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_unverified403L'application est en mode Réel et le propriétaire d'équipe n'a pas vérifié son e-mail.plan_limit403La requête dépasserait une limite de votre forfait, comme son nombre d'abonnés Réels.plan_read_only403Votre forfait a rendu cette application Réelle en lecture seule. Les lectures fonctionnent toujours, tout comme le débit d'une facture.not_found404L'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_found404Le lien de changement de formule est incorrect. Envoyez-en un nouveau au client avec Changer de formule.slug_taken409Un autre produit de l'application a déjà le slug que vous avez envoyé. Envoyez un slug différent.already_paid409La facture est déjà payée.invoice_not_open409La 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_canceled409L'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_active409Vous 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_scheduled409L'abonnement est déjà programmé pour être résilié, vous ne pouvez donc pas demander de résiliation.payment_in_progress409Un 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_unavailable409L'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_early409Le 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_inactive409L'offre de changement de formule a déjà été acceptée, annulée ou remplacée par une plus récente.session_not_open409La session est déjà terminée ou expirée, elle ne peut donc pas être expirée.idempotency_in_progress409Une requête avec la même Idempotency-Key est toujours en cours. Réessayez dans un instant.no_pending_change409Le tarif n'a aucun changement programmé à annuler.change_in_effect409Le 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.conflict409La requête entre en conflit avec l'état actuel de l'objet.price_archived410Le tarif est archivé, aucun nouvel abonnement ne peut l'utiliser.plan_offer_expired410L'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_expired410La 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_eligible422L'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_payments422L'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_unavailable422La méthode de paiement n'est pas proposée, ou ne prend pas les paiements dans la devise de la facture.idempotency_key_reused422L'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_missing422Vous avez demandé d'envoyer ou de renvoyer un webhook, mais l'application n'a pas d'URL de webhook.rate_limited429Trop de requêtes. Voir Limites de débit.internal500Quelque 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.
{
"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.
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
422avec le codeidempotency_key_reused. - Tant que la première requête est en cours, elle renvoie
409avec le codeidempotency_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
- Authentification et clés d'APIAuthentifiez vos requêtes avec votre clé secrète, et sachez quelle clé va où.
- Listes et filtresCe que renvoient les endpoints de liste, comment les paginer et les filtrer, et comment traiter les identifiants.
- AbonnementsDémarrez, listez, lisez, mettez à jour, annulez, conservez et changez la formule de l'abonnement d'un client à un tarif.