Introduction
L'API MaliaPay vous permet d'accepter les paiements mobiles et bancaires en Côte d'Ivoire. Une seule intégration pour accéder à Wave, Orange Money, MTN MoMo, Djamo, PeyaPay et les paiements par carte bancaire (Moov CI est momentanément indisponible).
https://business.malia.ci/api/v1
Format des requêtes
- Toutes les requêtes sont en JSON
- Header obligatoire :
Content-Type: application/json - Authentification marchand :
X-API-Key: VOTRE_CLE_API - Le champ
montantaccepteintoustringet est normalisé côté serveur - Le champ
customer_emailest facultatif
1. Authentification
L'API de paiement n'accepte qu'un seul mode d'authentification : la clé API (header X-API-Key).
Clé API — obligatoire
Envoyez votre clé API via le header X-API-Key. La clé est liée à un marchand actif et permet d'appeler les endpoints de paiement sans login préalable.
Le merchant_id présent dans le body est forcé côté serveur pour correspondre à celui de la clé API. Cela évite qu'un client paie au nom d'un autre marchand.
2. Clé API (X-API-Key)
Chaque marchand dispose d'une clé API unique, générée à la création du compte. Elle est visible dans votre espace marchand ; pour en obtenir une nouvelle, contactez le support.
Où trouver ma clé API ?
Connectez-vous à votre espace marchand : votre clé figure dans Intégration API → Vos identifiants et dans votre Profil (menu de votre compte, en haut à droite). Elle est masquée par défaut ; un bouton permet de l'afficher et de la copier.
Utiliser la clé API
Protection du merchant_id
Le middleware identifie le marchand grâce à la clé API et remplace le merchant_id du body par celui associé. Même si le client modifie merchant_id dans la requête, c'est la clé API qui fait autorité.
Ne partagez jamais votre clé API dans du code côté client. Stockez-la dans vos variables d'environnement et appelez l'API depuis votre backend.
3. Canaux de paiement
Utilisez ces codes pour spécifier le canal de paiement lors de la création d'une transaction.
| Canal | Code API | Type | Description |
|---|---|---|---|
| Wave CI | WAVECI | Mobile Money | Paiement via l'application Wave |
| Orange Money | OMCI | Mobile Money | Paiement via Orange Money CI |
| MTN MoMo | MTNCII | Mobile Money | Paiement via MTN Mobile Money |
| Moov CI | MOOVCI | Mobile Money | Paiement via Moov Money — momentanément indisponible |
| Djamo | DJAMO | Mobile Money | Paiement via l'application Djamo |
| PeyaPay | PEYA_PAY | Mobile Money | Paiement via PeyaPay (avec OTP) |
| Carte Bancaire | CARD | Carte | Paiement par carte Visa/Mastercard |
Le canal MOOVCI n'est pas disponible pour le moment. N'envoyez pas de paiement Moov et ne l'incluez pas dans vos tests ; nous annoncerons sa remise en service.
4. Créer un paiement
Cet endpoint crée une transaction de paiement et retourne une URL de redirection pour le client final.
Headers requis
Corps de la requête
Connectez-vous à votre espace marchand : votre ID Marchand (commençant par MI_) figure dans Intégration API → Vos identifiants et dans votre Profil.
Réponse succès (200/201)
Redirigez votre client vers l'URL retournée dans le champ link. Le client complètera le paiement directement avec l'opérateur.
Formats acceptés : 0700000000, +2250700000000 ou 225700000000. Le serveur normalise automatiquement les numéros avant d'appeler les opérateurs.
Avec MTNCII aucune redirection n'est retournée. Le statut est pending et le client reçoit une notification push/ USSD pour valider la demande. Surveillez le statut via GET /payments/{transaction_id} ou le webhook.
Flux de paiement par canal
Wave, Orange, Djamo
Redirection vers une page de confirmation. Le client valide sur son téléphone et retourne automatiquement.
PeyaPay
Nécessite une validation par OTP. Le client entre le code reçu par SMS sur la page de paiement.
Carte Bancaire
Redirection vers l'interface sécurisée de SycaPay pour saisie des informations de carte. À son retour, le client est renvoyé vers votre success_url ou error_url. La confirmation du paiement est vérifiée par MaliaPay auprès de l'opérateur : attendez la notification ou interrogez le statut, sans vous fier à la seule redirection.
5. PeyaPay (OTP)
Le canal PEYA_PAY fonctionne en deux étapes : une requête d'initiation envoie un OTP au client, puis une requête de vérification finalise le paiement.
Étape 1 — Initier
Le body est identique à la création de paiement standard, avec "channel": "PEYA_PAY" et un numéro de téléphone valide. La réponse contient peyapay_transaction_id à mémoriser.
Exemple de réponse (201)
Étape 2 — Vérifier le OTP
Le client reçoit un code par SMS et le renvoie via votre backend.
Étape 3 — Consulter le statut (optionnel)
Le endpoint verify est synchrone. En cas de traitement asynchrone, utilisez le statut PeyaPay pour suivre l'opération.
6. Vérifier le statut d'un paiement
Consultez le statut d'une transaction pour savoir si elle a été complétée, est en attente, ou a échoué.
Exemple de requête
-H "X-API-Key: sk_live_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json"
Réponse
Un paiement non confirmé par l'opérateur au bout de 10 minutes passe en failed. Si l'opérateur confirme ensuite le paiement (cas fréquent de la carte bancaire), il repasse en success et vous êtes notifié. Tenez toujours compte du dernier statut reçu.
Statuts possibles
| Statut | Description |
|---|---|
| pending | Paiement initié, en attente de confirmation client |
| processing | Paiement en cours de traitement chez l'opérateur |
| pending_otp | En attente de validation OTP (PeyaPay) |
| success | Paiement confirmé et réussi |
| failed | Paiement échoué (fonds insuffisants, erreur opérateur...) |
| cancelled | Paiement annulé par le client ou expiré |
7. Notifications (webhook)
Indiquez l'adresse de votre serveur dans le champ notification_url de chaque paiement. MaliaPay y envoie un POST JSON dès qu'un statut est confirmé : succès, échec, annulation ou traitement en cours.
La notification est envoyée avec un délai maximal de 10 secondes : votre endpoint doit répondre rapidement par un HTTP 2xx (200 recommandé). Si votre serveur répond autre chose ou ne répond pas à temps, MaliaPay renvoie la notification après 1 minute, puis 5 minutes, 15 minutes, 1 heure et 6 heures (5 relances, environ 7 h 20 en tout), puis abandonne. Si votre serveur a été indisponible plus longtemps, interrogez GET /api/v1/payments/{transaction_id}.
Contenu de la notification
Valeurs du champ status
| Statut | Signification |
|---|---|
| success | Paiement confirmé : vous pouvez valider la commande |
| failed | Paiement échoué, refusé ou non confirmé dans le délai |
| cancelled | Paiement annulé par le client |
| processing | Paiement en cours de traitement chez l'opérateur |
Vérifier la signature
Chaque notification porte deux en-têtes. Vous pouvez vérifier qu'elle vient bien de MaliaPay et qu'elle n'a pas été modifiée. Cette vérification est facultative : vos intégrations actuelles continuent de fonctionner sans changement.
| En-tête | Contenu |
|---|---|
X-MaliaPay-Timestamp | Horodatage Unix (secondes) de l'envoi |
X-MaliaPay-Signature | sha256= suivi du HMAC-SHA256 de {timestamp}.{corps brut}, calculé avec votre clé API |
Calculez la signature sur le corps brut reçu, sans le décoder ni le ré-encoder, comparez-la en temps constant, et rejetez les notifications dont l'horodatage a plus de 5 minutes pour éviter qu'une notification interceptée soit rejouée.
Confirmer avant de valider une commande
La signature prouve l'origine de la notification. Avant de livrer ou de valider une commande, relisez tout de même le statut auprès de MaliaPay avec votre clé API, et vérifiez la référence : une notification peut arriver dans le désordre ou être remplacée par une plus récente.
Répondez toujours HTTP 200. Traitez les notifications de façon idempotente : une même transaction peut être notifiée plusieurs fois (relances, ou statuts successifs comme d'abord failed puis success). Ne considérez pas la page de retour du client (success_url) comme une preuve de paiement.
8. Codes d'erreur
| Code HTTP | Erreur | Description |
|---|---|---|
| 401 | Unauthorized | Clé API absente, invalide, ou marchand inactif |
| 404 | Not Found | Transaction introuvable |
| 422 | Validation Error | Champ manquant ou invalide (canal inconnu, montant inférieur à 100, URL incorrecte…) |
| 502 | Gateway Error | L'opérateur a refusé la demande ou le canal est en maintenance : le champ reason donne la cause |
| 500 | Server Error | Erreur serveur, réessayez plus tard |
Erreur de validation (422)
Authentification ou opérateur (401, 502)
9. Exemples complets
Exemple PHP complet
Exemple JavaScript (Node.js)
Exemple Python
10. Bac à sable (sandbox)
Utilisez le bac à sable pour tester votre intégration sans effectuer de vrai paiement. L'endpoint accepte le même body que /payments mais ne déclenche aucun appel opérateur.
Comportement
- Mêmes règles de validation que
/payments - Mêmes frais calculés
- Crée une transaction enregistrée avec le statut
successetgateway_transaction_id=TEST - Aucun appel à Wave, Orange, MTN, Moov, Djamo ou SycaPay
- Ne simule que le succès : les scénarios d'échec, d'annulation, d'attente ou de confirmation tardive ne sont pas disponibles
- N'envoie aucune notification à votre
notification_url: testez la réception de vos webhooks avec un vrai paiement de faible montant - La transaction de test est enregistrée à part : elle n'apparaît pas dans votre historique et
GET /api/v1/payments/{transaction_id}la renvoie en 404
Exemple de requête
Réponse (201)
Utilisez ce endpoint pour valider votre clé API, votre format JSON et la structure des réponses avant de passer en production.
Support & contact
Besoin d'aide pour l'intégration ? Notre équipe technique vous accompagne par email : indiquez votre identifiant marchand et la référence de la transaction concernée.
Une solution proposée par Lkmdigital