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/referenceIdpour é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_idopé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_idest le verrou anti-doublon — obligatoire dans chaquePaymentRequest - 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¶
- telecom-distribution/api/momo-api-benin — endpoints détaillés, portails développeurs, contacts opérateurs
- telecom-distribution/index — index du projet