Passerelle de paiement MTN MoMo

Acceptez les paiements par mobile money des utilisateurs MTN Mobile Money (MoMo) à travers l’Afrique. S’intègre à l’API MTN MoMo Collections pour créer des transactions « Request to Pay », permettant aux clients d’approuver les paiements directement depuis leur téléphone.

Request to Pay

Initiez des demandes de paiement que les clients approuvent via une invite USSD sur leur téléphone MTN.

Provisionnement Sandbox

Génération en un clic des identifiants API sandbox directement depuis le panneau d’administration.

Vérification en temps réel

Vérification automatique du statut de paiement avec barre de progression. Support des webhooks pour les environnements de production.

Identifiants chiffrés

Tous les identifiants API sont chiffrés au repos en utilisant la façade Crypt de Laravel avant le stockage en base de données.

Cas d’utilisation

E-commerce en Afrique

Vous gérez une boutique en ligne sur Larapen ciblant les clients dans les pays desservis par MTN (Ouganda, Ghana, Cameroun, Côte d’Ivoire, Bénin, Congo, Libéria). Les clients paient leurs commandes en utilisant leur portefeuille MTN MoMo : aucune carte de crédit requise.

  • Installez les add-ons Shop et MoMo.
  • Configurez les identifiants MTN MoMo dans le panneau d’administration.
  • Les clients sélectionnent « MTN Mobile Money » au moment du paiement, entrent leur numéro de téléphone et approuvent le paiement sur leur téléphone.

Vente de produits numériques

Vous vendez des produits numériques (e-books, logiciels, modèles) à des utilisateurs mobile-first qui préfèrent le mobile money aux paiements par carte.

  • Combinez avec la livraison de produits numériques de l’add-on Shop.
  • Après confirmation du paiement MoMo, le lien de téléchargement est automatiquement fourni.

Réservation de services

Toute entité payable implémentant le contrat Payable peut utiliser MoMo pour le paiement, le rendant extensible au-delà de l’add-on Shop.

Prérequis

  • Larapen CMS v1.0.0 ou ultérieur
  • PHP 8.3+
  • MySQL 8.0+
  • L’add-on Shop (dépendance requise)
  • Un compte développeur MTN MoMo sur momodeveloper.mtn.com
  • Un abonnement au produit Collections sur le portail développeur MTN MoMo
Remarque : Pour les tests sandbox, seule la clé d’abonnement est requise : l’identifiant utilisateur API et la clé API peuvent être générés automatiquement via la fonctionnalité de provisionnement du panneau d’administration.

Installation

Étape 1 : Placer l’add-on

Copiez ou créez un lien symbolique du dossier momo dans le répertoire « extensions/addons » de votre Larapen :

Étape 2 : Activer l’add-on

Allez dans Admin → Add-ons → Add-ons installés et activez Passerelle de paiement MTN MoMo.

Dépendance : L’add-on Shop doit être installé et actif avant d’activer MoMo.

Étape 3 : Exécuter les migrations

Cela crée la table momo_transactions pour le suivi des références de paiement et des statuts.

Étape 4 : Définir les permissions

L’add-on enregistre 2 permissions (voir Permissions). Assignez-les aux rôles administrateur via Admin → Utilisateurs → Rôles & Permissions.

Étape 5 : Configurer

Naviguez vers Admin → MTN MoMo → Paramètres et configurez vos identifiants API. Pour les tests sandbox, utilisez la fonctionnalité de Provisionnement pour générer automatiquement les identifiants. Voir Configuration.

Configuration

Tous les paramètres sont gérés dans Admin → MTN MoMo → Paramètres (stockés dans la table settings, groupe momo). Les valeurs par défaut de configuration sont définies dans config/momo.php.

Paramètre Description Défaut
momo_subscription_key Ocp-Apim-Subscription-Key du portail développeur MTN MoMo. Stockée chiffrée. (vide)
momo_api_user_id UUID v4 de l’utilisateur API. Généré pendant le provisionnement ou obtenu depuis le portail partenaire MTN. Stocké chiffré. (vide)
momo_api_key Clé API générée pour l’utilisateur API. Stockée chiffrée. (vide)
momo_environment Environnement de déploiement : sandbox ou production. sandbox
momo_target_environment Valeur de l’en-tête d’environnement cible. sandbox pour les tests, ou un code spécifique au pays pour la production (voir Options de paiement). sandbox
momo_currency Code devise pour les paiements. Doit être EUR en sandbox. Spécifique au pays en production. EUR
momo_callback_host Votre domaine pour recevoir les callbacks webhook (production uniquement). Doit supporter HTTPS. (vide)

Variables d’environnement

Remarque : Les variables d’environnement sont utilisées comme valeurs par défaut. Les paramètres enregistrés dans le panneau d’administration les remplacent. Les identifiants API enregistrés via le panneau d’administration sont chiffrés avant le stockage.

Configuration du portail développeur MTN

  1. Créez un compte sur momodeveloper.mtn.com.
  2. Abonnez-vous au produit Collections.
  3. Naviguez vers votre page Profil et copiez la Clé primaire (ou Clé secondaire) : c’est votre Clé d’abonnement.
  4. Pour le sandbox : utilisez la fonctionnalité de Provisionnement du panneau d’administration pour générer automatiquement l’identifiant utilisateur API et la clé API.
  5. Pour la production : obtenez les identifiants depuis le Portail partenaire MTN MoMo et saisissez-les dans Identifiants API.
Important : Copiez la clé d’abonnement depuis votre page Profil, pas depuis la page du produit. La clé sur la page Profil est celle qui fonctionne avec l’API.

Admin : Paramètres

La page de paramètres (MTN MoMo → Paramètres) est organisée en quatre sections :

Provisionnement Sandbox

Cette section automatise le flux de génération des identifiants sandbox :

  1. Entrez votre Clé d’abonnement (depuis la page Profil du portail développeur MTN).
  2. Entrez optionnellement un Hôte de callback (par défaut webhook.site pour le sandbox).
  3. Cliquez sur Générer les identifiants API.
  4. Le système automatiquement :
    • Génère un UUID v4 pour l’identifiant utilisateur API
    • Crée l’utilisateur API via POST /v1_0/apiuser
    • Génère la clé API via POST /v1_0/apiuser/{id}/apikey
    • Chiffre et stocke les trois identifiants dans la base de données
    • Définit l’environnement à sandbox et la devise à EUR
  5. Les identifiants générés sont affichés une seule fois dans une alerte de succès avec des boutons de copie. Sauvegardez-les en externe : la clé API ne peut pas être récupérée à nouveau depuis MTN.

Tester la clé

Le bouton Tester la clé effectue un appel API de diagnostic (crée un utilisateur API temporaire) pour vérifier que la clé d’abonnement est valide. Renvoie HTTP 201 en cas de succès, avec les détails de requête/réponse pour le débogage.

Identifiants API

Trois champs de type mot de passe avec des boutons de basculement de visibilité :

  • Clé d’abonnement : Ocp-Apim-Subscription-Key depuis le portail MTN.
  • Identifiant utilisateur API : UUID v4 créé lors du provisionnement de l’utilisateur API.
  • Clé API : Générée à partir de l’utilisateur API.
Sécurité : Les trois identifiants sont chiffrés avec Crypt::encryptString() de Laravel avant d’être stockés en base de données. Ils ne sont déchiffrés que lorsqu’ils sont nécessaires pour les appels API. Laissez un champ vide pour conserver la valeur actuellement stockée.

Options de paiement

  • Environnement : sandbox ou production. Détermine quelle URL de base de l’API MTN est utilisée.
  • Environnement cible : Envoyé comme en-tête X-Target-Environment. Utilisez sandbox pour les tests, ou l’une des valeurs spécifiques au pays pour la production :
Pays Valeur d’environnement cible Devise
Ouganda mtnuganda UGX
Ghana mtnghana GHS
Cameroun mtncameroon XAF
Côte d’Ivoire mtnivorycoast XOF
Bénin mtnbenin XOF
Congo mtncongo XAF
Libéria mtnliberia LRD
Sandbox sandbox EUR
  • Devise : Doit correspondre à l’environnement cible (voir le tableau ci-dessus). Doit être EUR en sandbox.
  • Hôte de callback : Votre domaine pour recevoir les callbacks webhook (production uniquement). HTTPS est requis.

Informations d’intégration

Le bas de la page de paramètres affiche :

  • L’URL de callback (https://votre-domaine.com/momo/callback) à copier dans le portail MTN.
  • Une liste de référence de toutes les valeurs d’environnement cible valides par pays.

Flux de paiement

Le parcours de paiement complet du passage en caisse à la confirmation :

1. Sélection au passage en caisse

Le client sélectionne « MTN Mobile Money » comme méthode de paiement sur la page de paiement. Un champ de saisie du numéro de téléphone est affiché (la vue Blade momo::payment-form).

2. Saisie du numéro de téléphone

Le client entre son numéro de téléphone MTN MoMo (ex. +233XXXXXXXXX). Le numéro est normalisé (espaces, tirets et parenthèses supprimés) avant la soumission.

3. Création de la commande

Le formulaire est soumis via AJAX. L’add-on Shop crée l’enregistrement de commande, puis appelle MomoGateway::createPaymentIntent().

4. Request to Pay

La passerelle :

  1. Obtient un jeton Bearer OAuth2 depuis MTN (POST /collection/token/).
  2. Génère un identifiant de référence UUID pour la transaction.
  3. Envoie un « Request to Pay » à MTN (POST /collection/v1_0/requesttopay).
  4. Stocke un enregistrement MomoTransaction avec le statut PENDING.
  5. Retourne l’identifiant de référence au frontend.

5. Approbation USSD

Le client reçoit une invite USSD sur son téléphone MTN et entre son code PIN pour approuver le paiement.

6. Vérification côté frontend

Pendant que le client approuve, le JavaScript frontend interroge GET /momo/status/{referenceId} toutes les 5 secondes (configurable), affichant une barre de progression. Voir Mécanisme de vérification.

7. Confirmation

Lorsque la vérification renvoie succeeded, le frontend redirige vers GET /momo/confirm?reference_id={id}. La méthode MomoController::confirm() vérifie le statut final, marque la commande comme payée et redirige vers la page de succès de la commande.

Sandbox vs. Production : En sandbox, la vérification par interrogation est le mécanisme principal (pas de vraies invites USSD ni de callbacks). En production, la vérification par interrogation et les webhooks fonctionnent simultanément : le premier à confirmer déclenche la mise à jour de la commande.

Webhooks

En production, MTN MoMo envoie des callbacks à votre serveur lorsque le statut d’un paiement change. L’URL de callback est https://votre-domaine.com/momo/callback.

PUT /momo/callback
Description

Reçoit les callbacks de statut de paiement MTN MoMo. La protection CSRF est désactivée pour ce point de terminaison. Accepte également les requêtes POST pour plus de flexibilité.

Traitement

Le WebhookController délègue à MomoGateway::handleWebhook(), qui :

  1. Extrait le reference_id de l’en-tête X-Reference-Id ou des données.
  2. Trouve l’enregistrement MomoTransaction correspondant.
  3. Met à jour le statut de la transaction et l’identifiant de transaction financière.
  4. Si SUCCESSFUL : marque la commande comme payée et crée un enregistrement Transaction du Shop.
  5. Si FAILED : marque le paiement comme échoué et crée un enregistrement Transaction en échec.
Réponse (JSON)

Remboursements

Non supporté : L’API MTN MoMo Collections ne fournit pas de point de terminaison de remboursement. La méthode refund() renvoie un échec avec un message explicatif. Les remboursements doivent être traités manuellement via le Portail partenaire MTN MoMo ou via l’API Disbursements séparée.

Intégration avec l’add-on Shop

L’add-on MoMo s’intègre avec l’add-on Shop à travers le contrat PaymentGatewayInterface :

Découverte de la passerelle

La classe MomoGateway est taguée comme payment.gateways dans le conteneur de services. L’add-on Shop la découvre automatiquement aux côtés des autres passerelles de paiement (ex. Stripe).

Interface Payable

Le modèle Order du Shop implémente App\Contracts\Payable, qui fournit :

  • getPayableAmount() : le total de la commande
  • getPayableIdentifier() : le numéro de commande
  • getPaymentSuccessUrl() : URL de redirection après paiement réussi
  • getPaymentCancelUrl() : URL de redirection après paiement échoué/annulé
  • markAsPaid() : met à jour le statut de la commande à COMPLETED et le statut de paiement à PAID

Enregistrement des transactions

Deux types d’enregistrements de transaction sont créés :

  • MomoTransaction : suit l’identifiant de référence API MTN, le statut et le numéro de téléphone du payeur.
  • Transaction Shop : créée par le gestionnaire webhook/confirmation pour l’historique de paiement de la commande.

Support polymorphique

Le modèle MomoTransaction utilise une relation morphTo (payable_type / payable_id), permettant à tout modèle implémentant Payable d’utiliser MoMo pour les paiements : pas seulement les commandes du Shop.

Mise à jour

Étape 1 : Remplacer les fichiers

Remplacez le répertoire de l’add-on par la nouvelle version.

Étape 2 : Exécuter les migrations

Étape 3 : Vider les caches

Étape 4 : Vérifier

Visitez MTN MoMo → Paramètres et utilisez Tester la clé pour confirmer que vos identifiants fonctionnent toujours.

Sauvegarde préalable : Sauvegardez toujours votre base de données avant d’exécuter des migrations sur un système en production.

Dépannage

« Failed to obtain MTN MoMo access token »

Vérifiez que :

  • Les trois identifiants API (Clé d’abonnement, Identifiant utilisateur API, Clé API) sont correctement configurés.
  • La clé d’abonnement n’a pas expiré ou n’a pas été révoquée.
  • Votre serveur peut atteindre sandbox.momodeveloper.mtn.com (sandbox) ou proxy.momoapi.mtn.com (production).
  • L’identifiant utilisateur API et la clé API correspondent : ils doivent provenir de la même session de provisionnement.

Le provisionnement échoue : HTTP 401

  • Vérifiez que vous êtes abonné au produit Collections sur momodeveloper.mtn.com.
  • Copiez la Clé primaire depuis votre page Profil, pas depuis la page du produit.
  • Assurez-vous que l’abonnement est toujours actif (non expiré).
  • Vérifiez les espaces en début/fin lors du collage de la clé.

Le provisionnement échoue : HTTP 409

Un utilisateur API avec l’UUID généré existe déjà. Cliquez simplement sur Générer les identifiants API à nouveau : un nouvel UUID est généré à chaque fois.

« A phone number is required for MTN MoMo payments »

Le client n’a pas saisi son numéro de téléphone dans le formulaire de paiement. Assurez-vous que la vue du formulaire de paiement MoMo (momo::payment-form) est correctement chargée et que le champ de saisie du téléphone est visible lorsque MoMo est sélectionné comme méthode de paiement.

Le paiement reste « en attente » indéfiniment

  • En sandbox : utilisez l’un des numéros de téléphone de test (voir Tests Sandbox).
  • En production : le client n’a peut-être pas approuvé l’invite USSD sur son téléphone.
  • Après le délai d’expiration de la vérification (~5 minutes), un message de délai dépassé est affiché à l’utilisateur.
  • Le paiement peut encore être confirmé ultérieurement via webhook si le client approuve après le délai.

« Payment was declined or cancelled »

  • Le client a refusé l’invite USSD ou a saisi un code PIN incorrect.
  • Le compte MoMo du client a des fonds insuffisants.
  • Le code de raison MTN est ajouté au message d’erreur pour le débogage (ex. PAYER_NOT_FOUND, NOT_ENOUGH_FUNDS).

« Request was blocked » (réponse non JSON)

Un WAF (pare-feu d’application web) ou un proxy a bloqué la requête API. Cela peut arriver lorsque la passerelle API MTN rejette la requête au niveau de l’infrastructure. Vérifiez les journaux du serveur pour le corps de réponse complet et vérifiez votre clé d’abonnement et la configuration de l’hôte de callback.

Le webhook ne fonctionne pas en production

  • Assurez-vous que momo_callback_host est défini sur votre domaine (sans le préfixe https://).
  • L’hôte de callback dans vos paramètres doit correspondre au providerCallbackHost défini lors de la création de l’utilisateur API.
  • Votre serveur doit accepter les requêtes PUT et POST à /momo/callback sans vérification CSRF.
  • Vérifiez que HTTPS fonctionne correctement sur votre domaine.

Erreurs de non-concordance de devise

  • Le sandbox requiert EUR : toute autre devise échouera.
  • La production requiert la devise spécifique au pays correspondant à l’environnement cible (voir Options de paiement).

Numéros de téléphone de test Sandbox

Utilisez ces numéros de téléphone en mode sandbox pour tester différents résultats de paiement :

Numéro de téléphone Résultat
46733123453 Paiement réussi
46733123454 Paiement refusé
46733123455 Paiement refusé
46733123456 Paiement refusé

Cet article vous a-t-il été utile ?

Merci pour votre retour !

Besoin d'aide ? Créez un ticket de support

Créer un Ticket