Erreurs
Toute erreur a la même forme, quel que soit son origine :
{
"error": {
"code": "VALIDATION_ERROR",
"message": "amountUsdt doit être un montant décimal positif.",
"requestId": "40ca5413-..."
}
}Conservez le requestId
Il figure dans chaque réponse d'erreur et dans nos journaux. C'est le seul élément qui nous permet de retrouver votre requête exacte — sans lui, un signalement se résume à « ça n'a pas marché hier ».
Traitez le code, jamais le message
Le code est stable : il fait partie du contrat d'API. Le message est destiné à un humain, il est traduit et il peut être reformulé à tout moment.
Un client qui branche sa logique sur le texte du message casse à la première correction de formulation — et il casse silencieusement, puisque la requête répond toujours.
Erreurs de requête
| Code | HTTP | Signification | Conduite à tenir |
|---|---|---|---|
VALIDATION_ERROR | 400 | Un champ est absent, mal typé ou hors bornes. | Corrigez la requête. Ne réessayez pas à l'identique. |
UNAUTHORIZED | 401 | Clé API absente, expirée ou révoquée. | Vérifiez l'en-tête Authorization. |
FORBIDDEN | 403 | Clé valide, mais la portée ne couvre pas cette route. | Émettez une clé avec la bonne portée. |
NOT_FOUND | 404 | La ressource n'existe pas, ou ne vous appartient pas. | Un identifiant d'un autre marchand répond 404, jamais 403 : l'existence même n'est pas divulguée. |
CONFLICT | 409 | L'opération contredit l'état actuel. | Relisez la ressource avant de recommencer. |
Quotas et limites
| Code | HTTP | Signification | Conduite à tenir |
|---|---|---|---|
QUOTA_EXCEEDED | 429 | Le plafond mensuel de votre offre est atteint. | Les en-têtes X-RateLimit-Limit, X-RateLimit-Remaining et X-RateLimit-Reset donnent l'état exact. Changez d'offre ou attendez la période suivante. |
RATE_LIMITED | 429 | Trop de requêtes sur une fenêtre courte. | L'en-tête Retry-After donne le délai en secondes. Respectez-le : réessayer plus tôt prolonge la limitation. |
FEATURE_NOT_IN_PLAN | 403 | La fonction existe, mais pas dans votre offre. | Changez d'offre. Réessayer ne changera rien. |
Deux limites différentes, deux conduites
QUOTA_EXCEEDED porte sur le volume du mois ; RATE_LIMITED sur la cadence. La première ne se résout pas en attendant quelques secondes.
Erreurs de paiement
| Code | HTTP | Signification | Conduite à tenir |
|---|---|---|---|
PAYMENT_NETWORK_MISMATCH | 422 | Les fonds sont arrivés sur un autre réseau que celui du lien. | Non récupérable automatiquement. Contactez le support avec le txHash. |
PAYMENT_AMOUNT_MISMATCH | 422 | Le montant reçu sort de la tolérance de ±1 %. | Le payeur peut compléter tant que le lien n'a pas expiré. |
INVALID_STATE_TRANSITION | 409 | L'opération demandée est impossible depuis l'état actuel. | Par exemple demander un versement sur un paiement non confirmé. Relisez le statut. |
Erreurs de rails
Celles-ci ne viennent pas de votre requête : un service dont nous dépendons n'a pas répondu.
| Code | HTTP | Signification | Conduite à tenir |
|---|---|---|---|
CHAIN_UNAVAILABLE | 503 | Le nœud blockchain est injoignable. | Réessayez avec un délai croissant. |
RATE_UNAVAILABLE | 503 | Le prix marché est indisponible, ou trop ancien pour être appliqué. | Réessayez avec un délai croissant. La conversion reprend seule dès que la source répond. |
INBOUND_NETWORK_CLOSED | 409 | Ce réseau n'accepte momentanément pas de nouveaux paiements (maintenance, rotation de clé). | Temporaire : réessayez plus tard. À ne pas confondre avec un réseau non servi, qui rend VALIDATION_ERROR et ne rouvrira pas. |
CHANNEL_UNAVAILABLE | 409 | L'opérateur Mobile Money est coupé — incident, ou coupure décidée par l'administrateur. | Le message indique la raison. Réessayez plus tard. |
PAYOUT_CHANNEL_ERROR | 502 | L'agrégateur a refusé l'ordre de versement. | Refus explicite : vérifiez le numéro et le canal. |
PAYOUT_INDETERMINATE | 502 | L'ordre est parti, mais son issue est inconnue. | ⚠ Ne rejouez pas. Voir ci-dessous. |
FEE_CONFIGURATION_ERROR | 422 | La grille tarifaire est incohérente pour ce canal. | Anomalie de configuration : signalez-la, ne réessayez pas. |
PAYOUT_INDETERMINATE — ne rejouez jamais
C'est le seul cas où réessayer peut décaisser deux fois. L'ordre a été remis à l'agrégateur et nous n'avons pas obtenu son issue : l'argent est peut-être parti. Le versement reste visible et réconciliable, et la réconciliation tranchera. Interrogez son statut, n'en créez pas un second.
Erreur interne
| Code | HTTP | Signification |
|---|---|---|
INTERNAL_ERROR | 500 | Défaut de notre côté. |
Le détail n'est jamais divulgué — ni trace d'exécution, ni erreur de base, ni secret de prestataire. Le requestId nous permet de retrouver l'incident complet dans nos journaux.
Rejouer sans payer deux fois
Sur les routes qui créent quelque chose, l'en-tête Idempotency-Key rend le rejeu sûr : une même clé ne produit jamais deux ressources. C'est la réponse correcte à un réseau coupé au mauvais moment — vous ne savez pas si la requête est passée, vous la rejouez avec la même clé.
curl -X POST https://coinnectivepay-api-g34q.onrender.com/api/v1/payment-links \
-H "Authorization: Bearer $CPAY_API_KEY" \
-H "Idempotency-Key: cmd-2026-0001" \
-d '{ "reference": "CMD-0001", "amountUsdt": "25.500000" }'Quand réessayer
| Situation | Réessayer ? |
|---|---|
VALIDATION_ERROR, FORBIDDEN, FEATURE_NOT_IN_PLAN | Non — le résultat sera identique. |
RATE_LIMITED | Oui, après Retry-After. |
CHAIN_UNAVAILABLE, RATE_UNAVAILABLE, INTERNAL_ERROR | Oui, avec un délai croissant. |
INBOUND_NETWORK_CLOSED, CHANNEL_UNAVAILABLE | Oui, une fois la fermeture levée. |
PAYOUT_INDETERMINATE | Jamais — interrogez le statut. |
