Aller au contenu

Abstraction Mobile Money — Pattern Adapter + Facade (MTN MoMo, Moov Flooz, FedaPay)

Résumé

Modèle d'architecture pour unifier l'accès aux API Mobile Money béninoises (MTN MoMo, Moov Flooz) et à l'agrégateur FedaPay via un pattern Adapter + Facade. L'application ne connaît qu'une interface MobileMoneyProvider ; chaque opérateur dispose de son propre adaptateur qui traduit les appels génériques vers l'API spécifique. Le provider actif est sélectionné par configuration.

Complète shared/api/momo-api-benin qui documente les endpoints et les accès opérateurs.

Contenu structuré

Architecture globale

Application Logic (services, usecases)
        │
        ▼
MobileMoneyFacade  ──►  MTN MoMo Adapter   ──►  API MTN MoMo
                   ──►  Moov Flooz Adapter  ──►  API Moov Flooz
                   ──►  FedaPay Adapter     ──►  API FedaPay
  • MobileMoneyFacade : interface unique exposée au reste de l'application
  • Adapter : un par opérateur, traduit les appels génériques vers l'API native
  • Configuration : config/mobile_money.yaml + variables d'environnement pour les secrets

Interface commune (Python)

class TransactionStatus(Enum):
    PENDING = "PENDING"
    SUCCESSFUL = "SUCCESSFUL"
    FAILED = "FAILED"
    CANCELLED = "CANCELLED"

@dataclass
class PaymentRequest:
    payer: PartyInfo        # party_id_type: "MSISDN", party_id: "+229xxxxxxxx"
    payee: PartyInfo
    amount: MoneyAmount     # amount: float, currency: "XOF"
    external_id: str        # id côté marchand (idempotence)
    description: Optional[str] = None

class MobileMoneyProvider(ABC):
    def initiate_payment(self, request: PaymentRequest) -> PaymentResponse: ...
    def get_transaction_status(self, transaction_id: str) -> PaymentResponse: ...
    def refund(self, transaction_id: str, amount: Optional[MoneyAmount]) -> PaymentResponse: ...
    def get_account_balance(self) -> MoneyAmount: ...
    def validate_webhook(self, payload: dict, signature: str) -> bool: ...
    def parse_webhook(self, payload: dict) -> dict: ...

Adaptateurs par opérateur

Opérateur Auth Endpoints clés Statut
MTN MoMo OAuth2 + Ocp-Apim-Subscription-Key /v1_0/requesttopay, /v1_0/transaction/{id}, /v1_0/account/balance Sandbox disponible
Moov Flooz API Key/Secret ou JWT /api/v1/payment, /api/v1/transaction/{id} (à confirmer) Contrat manuel requis
FedaPay Bearer <token> POST /transactions, GET /transactions/{id}, POST /transactions/{id}/refund, GET /balance Sandbox disponible

Configuration YAML

providers:
  mtn_momo:
    enabled: true
    sandbox: true
    subscription_key: "${MTN_MOMO_SUB_KEY}"
    callback_url: "https://example.com/webhook/mtn"
  moov_flooz:
    enabled: false        # activer après contrat
    api_key: "${MOOV_API_KEY}"
    api_secret: "${MOOV_API_SECRET}"
  fedapay:
    enabled: true
    sandbox: true
    api_key: "${FEDAPAY_API_KEY}"
    api_secret: "${FEDAPAY_API_SECRET}"

Gestion des erreurs

Hiérarchie d'exceptions :

MobileMoneyError
├── AuthenticationError
├── ValidationError
├── NetworkError
└── ProviderError

  • Retry avec exponential backoff pour les erreurs temporaires (timeout, 5xx)
  • Logger requêtes/réponses en masquant les données sensibles

Sécurité

  • Secrets dans vault (AWS Secrets Manager, HashiCorp Vault ou env chiffrées) — jamais loggés
  • Validation des signatures webhooks : HMAC-SHA256 ou RSA selon le provider
  • Conformité BCEAO et ANRPT Bénin pour les données mobile money
  • PCI-DSS SAQ-AEP si absence de stockage de données de carte

Tests

Type Approche
Unit Mocker les appels HTTP (requests-mock / respx) par adaptateur
Intégration sandbox MTN MoMo sandbox + FedaPay sandbox
Contrat Vérifier que chaque adaptateur respecte MobileMoneyProvider
Scénarios Paiement réussi, échec, timeout, webhook valide/faux

Bonnes pratiques

  • Idempotence : utiliser external_id / referenceId pour éviter les doublons
  • TTL : respecter les délais d'expiration opérateurs (ex. 15 min request-to-pay MTN)
  • Devise : travailler exclusivement en XOF pour le Bénin
  • Journalisation : logger external_id, transaction_id opérateur, statut, timestamp
  • Monitoring : exporter taux de succès, latence, webhooks reçus → Prometheus

Points clés

  • Un seul contrat d'interface MobileMoneyProvider — l'application ignore quel opérateur est actif
  • FedaPay = voie rapide (un seul contrat technique pour MTN + Moov) ; MTN direct = meilleur contrôle à long terme
  • L'external_id est le verrou anti-doublon — obligatoire dans chaque PaymentRequest
  • Moov Flooz n'a pas de sandbox publique — prévoir FedaPay ou un mock complet pour les tests
  • Configuration YAML + env vars : ne jamais hardcoder les clés dans le code

Liens connexes