Les erreurs
Un statut HTTP, et un corps stable — le même pour toutes les ressources. Le code est le contrat : votre programme s’y fie ; le message est pour un humain, en français ou en anglais selon Accept-Language.
Le corps
{
"error": {
"type": "invalid_request_error",
"code": "operator_required",
"message": "Choisissez votre opérateur.",
"details": {
"operators": [
{
"code": "mtn",
"name": "MTN"
},
{
"code": "moov",
"name": "Moov"
}
]
},
"request_id": "req_01j9x3t8m2k4c7vd9qhs"
}
}Un code ne se retire jamais sans passer par les Changements. Citez request_id au support : il retrouve l’appel dans vos journaux.
Les codes
| Statut | code | Quand | Que faire |
|---|---|---|---|
| 400 | parameter_missing | Un champ requis manque ; « param » le nomme. | Ajoutez le champ. |
| 400 | parameter_invalid | Un champ ne se lit pas ou sort de ses bornes ; « param » le nomme quand il y en a un. | Corrigez la valeur d’après le message. |
| 400 | currency_unavailable | La monnaie n’est pas ouverte, ou pas à cet espace. | Choisissez une monnaie de votre espace. |
| 400 | limit_exceeded | Le montant dépasse un plafond du palier, en réel. | Un montant plus petit, ou un palier plus haut. |
| 400 | balance_insufficient | Le solde ne couvre pas le remboursement ou le retrait, frais compris. | Attendez des encaissements, ou demandez moins. |
| 400 | phone_invalid | Le numéro du payeur ne se lit pas : trop court, trop long, ou d’un format inconnu. | Envoyez-le au format international (+229…), ou précisez « country ». |
| 400 | operator_required | Le numéro peut appartenir à plusieurs opérateurs de son pays. | Demandez au payeur son opérateur, et passez « operator » avec un des codes de « details.operators ». |
| 400 | operator_unavailable | Aucun opérateur ouvert ne correspond à ce numéro, ou l’opérateur ne prend pas ce montant pour le moment. | Proposez un autre numéro ; GET /v1/payment_methods dit ce qui est ouvert. |
| 400 | country_unavailable | Le pays du numéro, ou sa monnaie, n’est pas ouvert. | Proposez un numéro d’un pays ouvert : GET /v1/payment_methods les liste. |
| 400 | exchange_rate_unavailable | Le payeur paie dans une autre monnaie que le paiement, et le taux du jour manque. | Réessayez un peu plus tard, ou proposez un numéro du pays de votre monnaie. |
| 400 | amount_out_of_range | Le montant sort des bornes de l’opérateur, dans la monnaie du payeur. | Lisez « details.min_amount » et « details.max_amount », dans « details.currency ». |
| 400 | idempotency_key_required | Un appel qui envoie une demande sur un téléphone, sans en-tête Idempotency-Key. | Tirez la clé de votre commande (cmd-42) : un second clic donnera la même. |
| 400 | refund_amount_too_high | Le montant dépasse ce qui reste à rendre sur le paiement. | Demandez au plus « details.remaining ». |
| 400 | refund_reason_invalid | Le motif n’est pas un de ceux que Payiz accepte. | Prenez-le dans GET /v1/refund_reasons. |
| 401 | missing_api_key | Aucune clé dans l’en-tête Authorization. | Envoyez « Authorization: Bearer sk_… ». |
| 401 | invalid_api_key | Clé inconnue, révoquée, expirée, d’un autre mode, ou appel depuis une adresse non autorisée. | Vérifiez la clé et ses adresses autorisées dans votre espace. |
| 402 | payment_declined | Payiz refuse cette demande. La raison n’est pas donnée. | Ne relancez pas : proposez un autre moyen au payeur. |
| 403 | insufficient_permissions | La clé n’a pas le geste que l’appel demande. | Donnez ce geste à la clé, ou servez-vous d’une autre. |
| 403 | merchant_inactive | L’espace est suspendu ou fermé. | Écrivez au support depuis votre espace. |
| 403 | live_mode_not_enabled | Une clé réelle, alors que le palier de l’espace n’ouvre pas le réel. | Terminez la vérification du compte dans votre espace. |
| 403 | direct_not_enabled | Une demande lancée par l’API en réel, alors que le paiement direct n’est pas ouvert à l’espace. | Envoyez « payment_url » au payeur, ou demandez l’ouverture du direct. |
| 403 | not_permitted | Le geste est refusé pour cet espace. | Lisez le message ; écrivez au support si besoin. |
| 404 | resource_missing | L’objet n’existe pas, ou pas pour cette clé et ce mode. | Vérifiez l’identifiant et le mode de la clé. |
| 409 | idempotency_key_reuse | La même clé d’idempotence revient avec un autre corps, ou pendant que la première demande s’exécute. | Une clé par demande ; rejouez la même demande à l’identique. |
| 409 | payment_closed | Le paiement est payé, annulé ou expiré. | Lisez son état dans « details.status ». |
| 409 | attempt_in_progress | Une demande attend déjà la validation du payeur. | Attendez son issue, par webhook. |
| 409 | payment_disputed | Le paiement est contesté : la somme est déjà retenue. | Attendez l’issue du litige. |
| 409 | payment_not_refundable | Le paiement ne peut plus être remboursé (déjà rendu, ou en cours de remboursement). | Lisez le paiement et ses remboursements. |
| 409 | recipient_not_ready | Par sécurité, un bénéficiaire neuf ne reçoit qu’après un délai. | Réessayez après « details.usable_at ». |
| 409 | conflict | L’objet n’est pas dans un état qui permet ce geste. | Relisez l’objet, puis décidez. |
| 409 | setting_missing | Un réglage de la plateforme manque : c’est à Payiz de le poser. | Écrivez au support avec le « request_id ». |
| 413 | payload_too_large | Le corps dépasse la taille permise. | Allégez la demande. |
| 429 | rate_limited | Trop d’appels pour cette clé dans la minute. | Attendez le délai de l’en-tête Retry-After, puis reprenez. |
| 429 | too_many_attempts | Trop de demandes vers ce numéro en peu de temps. | Attendez avant de relancer : on ne harcèle pas un téléphone. |
| 500 | internal_error | Une erreur chez Payiz. | Réessayez avec la même clé d’idempotence ; citez le « request_id » au support. |
| 503 | payout_unavailable | Aucune voie ne peut envoyer ce retrait pour le moment. | Réessayez plus tard. |
| 503 | service_unavailable | Un service dont l’appel dépend ne répond pas. | Réessayez avec la même clé d’idempotence. |
Un paiement qui échoue chez le payeur n’est pas une erreur d’appel : la demande le dit, avec son failure_code. Voir Le paiement direct.
Où regarder
Chaque appel, sa réponse et sa durée s’inscrivent dans Développeurs › Journaux, gardés 30 jours : c’est là qu’on comprend une intégration qui coince.