Erreurs et limites

Le code est `status`, jamais `code`. Quotas, taille de corps, support.

La forme d'une erreur

{
  "success": false,
  "status": "AMOUNT_OUT_OF_RANGE",
  "message": "Montant hors limites",
  "data": { "minAmount": "100", "maxAmount": "1000000", "providedAmount": "50" }
}

Le code machine-lisible est status. Il n'y a pas de champ code, et il n'y a pas d'objet error imbriqué. Une intégration qui lit error.code lit undefined sur toutes les erreurs.

errors n'est présent que sur les erreurs de validation de schéma. data n'est présent que là où l'erreur transporte quelque chose d'utile : { orderId, status } sur un 409 d'orderId déjà pris, { workflow } sur un 422, { minAmount, maxAmount, providedAmount } (en plus petite unité, donc string plutôt qu'un number qui perdrait la précision) sur un 400 AMOUNT_OUT_OF_RANGE — minAmount/maxAmount couvrent l'enveloppe des corridors candidats pour ce couple numéro/devise, pas une garantie qu'un montant dans cette plage aurait été accepté : deux corridors peuvent couvrir des tranches disjointes. maxAmount est absent dès qu'un candidat n'a pas de plafond. Le 409 d'un renvoi de webhook hors statut terminal, lui, n'en porte pas.

message n'est pas contractuel

Les messages sont rédigés en français, et Accept-Language n'est pas pris en compte : il n'existe pas de version anglaise. Leur formulation peut changer sans préavis.

Ne faites jamais de correspondance sur le texte de message. Branchez-vous sur status, et affichez à vos utilisateurs vos propres libellés.

Ceci concerne les erreurs API (4xx/5xx). Pour l'échec d'une transaction (status: "failed" ou "cancelled"), voir Causes d'échec : même principe, failureCategory est la valeur normalisée, failureReason et failureCode le détail brut non contractuel.

Sur toute erreur de code HTTP 500 ou plus, message est remplacé par « Une erreur est survenue » : ces messages-là sont écrits pour l'exploitant az54 et ne vous sont pas destinés. Le status reste, lui, informatif.

Table des status

HTTPstatusQuand
400VALIDATION_ERRORCorps non conforme au schéma, ou montant plus précis que la devise.
400BAD_REQUESTRequête recevable par le schéma mais inexploitable (opérateur indétectable, par exemple).
400INVALID_BODYCorps illisible (JSON malformé).
400AMOUNT_OUT_OF_RANGEMontant hors des bornes du corridor.
400CORRIDOR_NOT_FOUNDAucun corridor actif pour ce couple numéro / devise.
401UNAUTHORIZEDClé absente, malformée ou révoquée.
403<PORTÉE>_NOT_ALLOWEDClé d'API sans la portée requise (PAYOUT_INITIATE_NOT_ALLOWED, par exemple).
403FORBIDDENRôle insuffisant, ou permission non attribuable à une clé d'API.
4032FA_REQUIREDSecond facteur requis. Session du tableau de bord seulement : une clé n'y est pas soumise.
404NOT_FOUNDRessource inexistante, ou orderId ambigu sur le reçu public.
409CONFLICTCet orderId existe déjà pour votre organisation, ou renvoi de webhook hors statut terminal.
413PAYLOAD_TOO_LARGECorps au-delà de 10 ko.
415UNSUPPORTED_MEDIA_TYPEContent-Type non supporté.
422OTP_REQUIREDLe corridor payant exige un OTP absent.
422REDIRECT_URLS_REQUIREDLe corridor payant exige des redirectUrls absentes.
429TOO_MANY_REQUESTSQuota dépassé.
502<PSP>_ERRORLe prestataire a échoué ou n'a pas répondu.

La dernière ligne n'est pas une valeur fixe : le status est construit à l'exécution à partir du code du prestataire qui a échoué. Traitez tout 502 par le suffixe _ERROR, ou plus simplement par son code HTTP.

<PORTÉE>_NOT_ALLOWED n'est pas non plus une valeur fixe : c'est le nom de la portée manquante suivi de _NOT_ALLOWED (PAYIN_INITIATE, PAYOUT_INITIATE, PAYOUT_APPROVE, TRANSACTIONS_VIEW, WEBHOOKS_MANAGE, et la liste peut s'allonger). Routez sur le suffixe _NOT_ALLOWED : la clé n'a pas ce droit, et la corriger passe par une clé créée avec la bonne portée (Authentification).

Un 502 ne signifie pas « échec ». Il signifie « issue indéterminée » : voir Idempotence.

Quotas

L'API générale accepte 1000 requêtes par tranche de 15 minutes, comptées par clé d'API. Le quota courant est lisible sur chaque réponse :

RateLimit-Limit: 1000
RateLimit-Remaining: 997
RateLimit-Reset: 812

Deux plafonds s'ajoutent à celui-là, sur leurs endpoints seulement :

  • 3 par minute et par transaction sur POST /v1/transactions/by-id/{transactionId}/resend-callback (Réconciliation) ;
  • ceux du reçu public, nettement plus stricts, qui lui sont propres.

Taille de corps

Les corps de requête sont plafonnés à 10 ko. Au-delà, 413 PAYLOAD_TOO_LARGE. C'est très largement suffisant pour un pay-in ; si vous approchez cette limite, c'est probablement que vous essayez d'envoyer des données qu'aucun champ du schéma n'accepte.

Support

Envoyez un en-tête x-correlation-id sur vos requêtes : il est repris tel quel et renvoyé dans la réponse. En son absence, az54 en génère un — il est de toute façon présent dans les en-têtes de réponse.

C'est la référence à citer au support, avec le transactionId s'il y en a un. Ni orderId seul, ni l'horodatage ne permettent de retrouver une requête aussi sûrement.

On this page