Gestion des erreurs
L'API utilise les codes HTTP standard. Le paiement direct renvoie en plus un code d'erreur stable, à tester dans votre programme plutôt que le message :
{"error": {"code": "invalid_amount", "message": "Le montant doit être compris entre 100 et 2000000.", "minimum": 100, "maximum": 2000000}}
Les autres points d'accès renvoient {"detail": "…"}, ou une liste d'erreurs par champ :
{"fixed_amount": ["Obligatoire quand le montant est fixe (is_amount_fixed=true)."]}
Codes de réponse
| HTTP | Code | Cause | Que faire |
|---|---|---|---|
200 201 | Succès | Lire la réponse | |
202 | Paiement en attente de confirmation | Attendre le webhook | |
400 | invalid_request | Champ manquant ou mal formé (détail dans details) | Corriger la requête |
400 | invalid_amount | Montant hors limites | Respecter minimum et maximum |
400 | invalid_phone | Numéro invalide pour le pays | Vérifier le numéro et dial_code |
400 | invalid_provider | Moyen de paiement inconnu ou inactif | Utiliser un moyen actif de votre projet |
400 | otp_required | Code OTP absent (Orange, Sank) | Demander le code au client |
401 | authentication_failed | Clé absente, invalide ou désactivée | Vérifier X-Api-Key |
402 | Paiement refusé par l'opérateur | Afficher message au client | |
403 | Adresse IP non autorisée, ou action réservée à votre espace | Vérifier vos adresses IP autorisées | |
404 | Ressource introuvable ou d'un autre projet | Vérifier l'identifiant | |
409 | idempotency_conflict | Requête avec la même Idempotency-Key encore en cours | Réessayer quelques secondes plus tard |
422 | idempotency_key_reused | Même Idempotency-Key, autre contenu | Nouvelle clé pour un nouveau paiement |
429 | Trop de requêtes | Attendre Retry-After secondes | |
500 | payment_unrecorded | Paiement transmis à l'opérateur mais non enregistré | Ne pas renvoyer : contacter le support |
502 | provider_error | Opérateur injoignable, aucun débit | Renvoyer avec la même Idempotency-Key |
Exemple de traitement
- Python
- Node.js
errors.py
class IntegralPayError(Exception):
def __init__(self, status, code, message):
super().__init__(message)
self.status, self.code, self.message = status, code, message
def call(method, path, **kwargs):
resp = session.request(method, f"{API_BASE}{path}", timeout=30, **kwargs)
if resp.status_code < 400 or resp.status_code == 402:
return resp.status_code, resp.json() # 402 : paiement refusé, réponse normale à afficher
data = resp.json() if resp.headers.get("Content-Type", "").startswith("application/json") else {}
error = data.get("error") or {}
raise IntegralPayError(resp.status_code, error.get("code", ""), error.get("message") or data.get("detail") or str(data))
errors.js
class IntegralPayError extends Error {
constructor(status, code, message) {
super(message);
Object.assign(this, { status, code });
}
}
async function call(method, path, body) {
const { status, data } = await api(method, path, body); // voir « Authentification »
if (status < 400 || status === 402) return { status, data };
const error = data.error || {};
throw new IntegralPayError(status, error.code || '', error.message || data.detail || JSON.stringify(data));
}