Aller au contenu

Erreurs

Format des erreurs 221 Pay, erreurs par champ, limite de requêtes, codes stables et conduite à tenir pour chacun.

Toute erreur de l’API 221 (221 Pay, routes de données, routes de projet, 404 et 405 compris) a la même enveloppe : un code stable à tester dans le code, un message lisible, un request_id à transmettre au support, fields quand des champs sont refusés, et des membres propres au code (limit, reset_at, retry_after_s…), au même niveau.

400 · application/json
{
  "code": "INVALID_REQUEST",
  "message": "Certains champs sont invalides.",
  "request_id": "2f6c9a0e-5b1d-4e7f-8c3a-9d0b1e2f3a4c",
  "fields": {
    "customer_phone": "Numéro mobile invalide pour le pays de ce moyen de paiement.",
    "offer_code": "offer_code doit contenir de 4 à 16 lettres ou chiffres."
  }
}
  • Tester code, jamais message ni le statut HTTP : le texte peut changer, et un même code peut porter un statut différent selon la route.
  • fields regroupe un message par champ refusé, pour afficher chaque erreur à côté de son champ.
  • message est en français ; en anglais avec Accept-Language: en ou le paramètre ?lang=en.
  • request_id est aussi renvoyé dans l’en-tête X-Request-Id de chaque réponse.

Limite de requêtes

600 requêtes par minute et par projet. Au-delà : 429 RATE_LIMITED, avec l’en-tête Retry-After, le délai d’attente en secondes.

429
HTTP/1.1 429 Too Many Requests
Retry-After: 12

C’est la seule limite des routes 221 Pay : le quota quotidien (429 QUOTA_EXCEEDED) ne concerne que les routes de données. Voir Authentification, section « Quota quotidien ».

Méthode non autorisée

Une route de /v1 appelée avec une autre méthode HTTP répond 405 avec l’en-tête Allow, la liste des méthodes acceptées, et la même enveloppe que les autres erreurs, avec le code METHOD_NOT_ALLOWED. Le message suit Accept-Language (français par défaut, anglais si la valeur commence par en).

405
HTTP/1.1 405 Method Not Allowed
Allow: GET, POST
Content-Type: application/json

{"code": "METHOD_NOT_ALLOWED", "message": "Méthode non autorisée. Méthodes acceptées : GET, POST.", "request_id": "2f6c9a0e-5b1d-4e7f-8c3a-9d0b1e2f3a4c"}

Codes

HTTPcodeCauseConduite
400INVALID_REQUESTCorps, paramètre ou en-tête invalide. fields donne un message par champ refusé, y compris un offer_code mal formé, un champ inconnu du corps de POST /v1/payments (fields.<nom du champ>), un Idempotency-Key absent sur POST /v1/payments, /v1/refunds ou /v1/payouts (clé Idempotency-Key), ou un remboursement supérieur au reste remboursable (fields.amount).Corriger les champs indiqués.
400OFFER_INVALIDCode promo inconnu, expiré ou hors des conditions de la commande.Retirer le code promo ou en utiliser un autre.
400PROJECT_REQUIREDSession du tableau de bord sans projet désigné.Envoyer l’en-tête X-221-External-Ref, ou appeler avec la clé du projet.
400BELOW_MINIMUMVirement bancaire sous le minimum. Champs min_amount et max_amount, et fields.amount.Envoyer au moins min_amount. Voir Retraits.
400ABOVE_MAXIMUMVirement bancaire au-dessus du maximum par retrait. Champs min_amount et max_amount, et fields.amount.Réduire le montant ou faire plusieurs retraits.
400INVALID_CODECode de vérification d’un compte de retrait incorrect. Champ attempts_left.Saisir le code reçu par e-mail.
400MISSING_CAPTURESVérification d’identité envoyée sans toutes les photos (/v1/kyc/...). Champ missing, la liste des photos à envoyer.Envoyer les photos manquantes, puis renvoyer la vérification.
401INVALID_API_KEYClé mal formée, inconnue ou révoquée.Vérifier la clé. Voir Authentification.
401UNAUTHENTICATEDNi clé ni session, ou clé d’un autre projet.Envoyer la clé du projet.
403MISSING_SCOPEClé sans la portée exigée par la route (payments, data) ou par l’événement webhook. Membre scope.Créer une clé avec cette portée.
403LIVE_NOT_ENABLEDAppel en mode live (clé sk_221_pay_live_…) sur un projet dont le mode live n’est pas activé.Faire activer le mode live par un administrateur du projet (voir Authentification), ou appeler avec une clé de test.
403FORBIDDENRôle insuffisant pour l’action.Agir avec un compte administrateur ou une clé API.
403KYC_REQUIREDRetrait ou numéro de retrait avant vérification d’identité. Champ kyc_status.Terminer la vérification. Voir Retraits.
403MERCHANT_SUSPENDEDCompte marchand suspendu ou fermé. Champ merchant_status.Contacter 221. Les lectures restent possibles.
403MERCHANT_LIMIT_EXCEEDEDPlafond journalier ou mensuel atteint. Champs limit_type (daily ou monthly) et limit.Attendre la période suivante ou demander un relèvement.
403WITHDRAWAL_LIMIT_EXCEEDEDPlafond de retrait atteint. Champs limit_type (per_withdrawal, daily_count, daily_amount ou monthly_amount) et limit.Réduire le montant, ou attendre la remise à zéro (minuit, heure de Dakar).
403MONTHLY_LIMIT_REACHEDTotal mensuel des virements bancaires atteint. Champ remaining, le montant encore possible ce mois-ci.Réduire le montant à remaining au plus, ou attendre le 1er du mois suivant.
404NOT_FOUNDObjet inexistant ou d’un autre projet.Vérifier l’identifiant.
404FEATURE_DISABLEDFonction désactivée par 221 (codes promo, par exemple).Appeler sans cette fonction.
409DUPLICATE_MERCHANT_REFERENCEmerchant_reference déjà utilisée dans le projet.Rejouer avec l’Idempotency-Key d’origine pour retrouver le paiement, ou choisir une nouvelle référence pour une nouvelle commande.
409IDEMPOTENCY_CONFLICTIdempotency-Key déjà utilisée avec un autre corps.Rejouer le corps d’origine.
409QUOTE_EXPIREDDevis de remboursement ou de retrait expiré (2 minutes). fields.quote_hash porte le message.Demander un nouveau devis.
409QUOTE_INVALIDquote_hash inconnu, déjà utilisé, d’un autre compte marchand, ou qui ne correspond pas à la requête (autre montant, autre fee_payer). fields.quote_hash porte le message.Demander un nouveau devis.
409DESTINATION_NOT_VERIFIEDDevis ou retrait vers un numéro ou un compte bancaire dont le code de vérification n’a pas été saisi. Le message dit « numéro » ou « compte bancaire » selon la destination.Saisir le code, puis réessayer. Voir Retraits.
409INSUFFICIENT_FUNDSSolde disponible insuffisant.Attendre de nouveaux encaissements ou réduire le montant.
409INVALID_STATEL’objet n’est pas dans un état qui permet l’action : litige déjà ouvert sur le paiement, ou litige qui ne peut plus être accepté, contesté ou complété ; numéro de retrait déjà vérifié (/resend). Le message nomme l’état actuel.Relire l’objet et agir selon son état.
409KYC_ALREADY_SUBMITTEDVérification d’identité déjà envoyée à l’examen (/v1/kyc/...).Ne pas la renvoyer : suivre GET /v1/kyc/status.
409OFFER_CODE_TAKENPOST /v1/offers avec un code promo qui existe déjà sur le projet.Choisir un autre code.
410CODE_EXPIREDCode de vérification d’un compte de retrait expiré (10 minutes).Demander un nouveau code avec POST /v1/payout-destinations/{id}/resend.
413REQUEST_TOO_LARGECorps de requête de plus de 1 Mio sur une route 221 Pay (l’envoi d’une pièce de litige a sa propre limite), de plus de 64 Kio sur une route de données.Réduire le corps.
429TOO_MANY_ATTEMPTS5 essais incorrects sur le code de vérification.Demander un nouveau code.
429RATE_LIMITEDLimite de requêtes atteinte. Les routes de données ajoutent le membre retry_after_s.Attendre Retry-After secondes.
500INTERNAL_ERRORErreur interne imprévue de 221 Pay.Rejouer avec la même Idempotency-Key et le même corps ; si elle persiste, transmettre le request_id à 221.
503CHANNEL_UNAVAILABLEMoyen de paiement non activé sur le projet ou momentanément fermé. Pour un retrait, les fonds réservés sont restitués avant la réponse.Proposer un autre moyen de paiement ou réessayer plus tard.
503PAYMENTS_UNAVAILABLE221 Pay momentanément indisponible sur ce serveur.Réessayer plus tard, avec la même Idempotency-Key.
503NOT_CONFIGUREDFonction non installée sur ce serveur : vérification d’identité (/v1/kyc/...) ou adresse publique des liens de paiement (POST /v1/payment-links). Différent de CHANNEL_UNAVAILABLE : ici rien n’est à réessayer.Contacter 221 avec le request_id.
507STORAGE_FULLStockage des photos de vérification d’identité momentanément plein (/v1/kyc/...).Réessayer plus tard.

Codes des routes de données et de projet

Ces codes, écrits en majuscules comme les autres, viennent des routes de données, des clés, des webhooks et de l’équipe d’un projet. Les membres propres au code sont au premier niveau du corps, à côté de message. Le statut HTTP peut varier selon la route : tester code.

HTTPcodeCauseMembres
400BAD_REQUESTCorps JSON illisible ou absent sur une route de données ou de projet (aucun fields). Un champ de type incorrect donne plutôt INVALID_REQUEST avec fields.
401API_KEY_EXPIREDClé expirée.expires_at
401API_KEY_REVOKEDClé révoquée.revoked_at
403API_KEY_DISABLEDClé désactivée par 221 pour usage abusif.disabled_at
403FORBIDDEN_ROLERôle du projet insuffisant pour l’action.role, required
429QUOTA_EXCEEDEDQuota quotidien des routes de données atteint.limit, reset_at
400INVALID_URLURL de webhook refusée (https vers un hôte public).fields.url
409SUBSCRIPTION_EXISTSCette URL a déjà un point de terminaison.url
409SUBSCRIPTION_LIMIT5 points de terminaison par projet atteints.limit
409KEY_LIMIT_REACHED5 clés actives par projet atteintes.limit
409PROJECT_LIMIT_REACHEDLimite de projets atteinte.limit
404PROJECT_NOT_FOUNDProjet inexistant ou qui n’est pas à l’appelant.
409LAST_ADMINLe projet doit garder un administrateur.
403OWNER_PROTECTEDSeul le titulaire change son rôle ou quitte le projet.
409OWNER_MUST_STAYLe titulaire reste administrateur.
409ALREADY_MEMBER, ALREADY_INVITEDPersonne déjà membre, ou invitation déjà en attente.email
404INVITATION_NOT_FOUNDInvitation inconnue ou retirée.
410INVITATION_EXPIREDInvitation expirée.expires_at
410INVITATION_USEDInvitation déjà utilisée.
403INVITATION_EMAIL_MISMATCHInvitation adressée à une autre adresse.
409EMAIL_NOT_VERIFIEDAdresse e-mail non confirmée.
403REAUTHENTICATION_REQUIREDReconnexion de moins de 10 minutes exigée.
403INVALID_PASSWORDMot de passe incorrect.
409BALANCE_NOT_EMPTYSuppression du projet impossible tant que des fonds ou un retrait sont en cours.reason
503DATASET_UNAVAILABLEJeu de données pas encore publié.dataset
503SERVER_BUSYService occupé : réessayer dans quelques secondes.

Les routes /auth (connexion, mot de passe) répondent aussi avec une forme plate code, message et request_id (aussi dans l’en-tête X-Request-Id). Leurs codes sont ceux du service de connexion, par exemple INVALID_EMAIL, INVALID_EMAIL_OR_PASSWORD ou VALIDATION_ERROR (corps illisible, avec un seul message générique). TOO_MANY_REQUESTS ajoute retry_after_s et l’en-tête X-Retry-After.

Réessayer sans risque

SituationRéessai
400, 401, 403, 404, 409Non : corriger d’abord la requête.
429Oui, après Retry-After secondes.
500, 503, délai dépassé, coupure réseauOui, avec la même Idempotency-Key et le même corps.
5xx sur un devisOui : un devis ne déplace pas d’argent.

POST /v1/payments, POST /v1/refunds et POST /v1/payouts exigent Idempotency-Key : un réessai ne crée jamais une seconde opération. Voir Paiements, section « Issue inconnue ».

Signaler un incident

Transmettre à 221 le request_id, l’heure de l’appel et la route appelée. Jamais la clé API ni le secret de webhook.