E-commerce13 min de lecture

Headless commerce Medusa + Wave + MTN MoMo : monter une boutique pan-africaine en 14 jours

Mohamed Bah·Fondateur, Kolonell
7 mai 2026
Partager :
Headless commerce Medusa + Wave + MTN MoMo : monter une boutique pan-africaine en 14 jours

Headless commerce Medusa + Wave + MTN MoMo : monter une boutique pan-africaine en 14 jours

E-commerce

Shopify est la solution facile, mais 4 % de commission sur 50M FCFA/mois = 2M FCFA/mois jeté. Pour un e-commerce qui scale au-delà de 30M FCFA mensuel — typiquement les marketplaces Lagos, Abidjan, Nairobi, Douala — Medusa devient la bonne réponse. Voici comment monter une stack pan-africaine.

TL;DR

- Medusa = backend Node.js + Postgres open-source, frontend Next.js de votre choix.

- Coût hébergement : 35-80€/mois (Hetzner Cloud + Neon Postgres) vs 80€/mois Shopify Basic + 4 % de fees.

- Couverture paiement : Wave (SN, CI), MTN MoMo (CI, GH, NG, CM, UG, RW, ZM), Airtel Money (NG, KE, TZ, MW), Orange Money (SN, CI, CM, ML, BF, GN, MG), M-Pesa (KE, TZ).

Pourquoi Medusa pan-africain en 2026

Le commerce en Afrique se fragmente par devise et passerelle :

  • UEMOA (XOF) : Wave + Orange Money + PayDunya
  • CEMAC (XAF) : Orange Money + MTN MoMo + Express Union
  • Nigeria (NGN) : Paystack + Flutterwave + Squad
  • Ghana (GHS) : MTN MoMo + Vodafone Cash + Hubtel
  • Kenya/Tanzanie (KES/TZS) : M-Pesa + Tigo Pesa + Stripe
  • Rwanda/Ouganda (RWF/UGX) : MTN MoMo + Airtel Money

Shopify ne supporte nativement aucun de ces moyens (sauf Stripe/Paystack via partenaires). Medusa permet de coder un PaymentProvider par passerelle et de couvrir 19 pays africains.

Architecture cible

`

[Next.js storefront]

[Medusa.js backend (Node)]

[Postgres (Neon)] + [Redis (Upstash)]

[Custom Payment Providers]

├── WavePaymentProvider (UEMOA)

├── MtnMomoPaymentProvider (Anglophone + CEMAC)

├── MPesaPaymentProvider (Afrique de l'Est)

├── PaystackPaymentProvider (NG, GH)

└── StripePaymentProvider (international)

[Algolia (search) + Cloudinary (images)]

`

Étape 1 — initialiser Medusa

`bash

# Crée le backend

npx create-medusa-app@latest --skip-db

cd kolonell-store

yarn install

`

Configurez medusa-config.js :

`js

module.exports = defineConfig({

projectConfig: {

redis_url: process.env.REDIS_URL,

database_url: process.env.DATABASE_URL,

database_type: 'postgres',

},

modules: [

{ resolve: '@medusajs/cache-redis', options: { redisUrl: process.env.REDIS_URL } },

{ resolve: '@medusajs/event-bus-redis', options: { redisUrl: process.env.REDIS_URL } },

{ resolve: './src/modules/wave-payment' },

{ resolve: './src/modules/mtn-momo-payment' },

{ resolve: './src/modules/mpesa-payment' },

],

});

`

Étape 2 — Wave Payment Provider (custom)

`ts

// src/modules/wave-payment/service.ts

import { AbstractPaymentProvider } from '@medusajs/framework/utils';

class WavePaymentProvider extends AbstractPaymentProvider {

static identifier = 'wave';

async initiatePayment({ amount, currency_code, data }) {

const res = await fetch('https://api.wave.com/v1/checkout/sessions', {

method: 'POST',

headers: {

'Authorization': Bearer ${process.env.WAVE_API_KEY},

'Content-Type': 'application/json',

},

body: JSON.stringify({

amount: String(amount),

currency: currency_code.toUpperCase(),

success_url: data.success_url,

error_url: data.error_url,

client_reference: data.cart_id,

}),

});

const session = await res.json();

return { data: { wave_id: session.id, wave_launch_url: session.wave_launch_url } };

}

async authorizePayment({ data }) {

const res = await fetch(

https://api.wave.com/v1/checkout/sessions/${data.wave_id},

{ headers: { 'Authorization': Bearer ${process.env.WAVE_API_KEY} } }

);

const session = await res.json();

return {

status: session.payment_status === 'succeeded' ? 'authorized' : 'pending',

data: session,

};

}

async capturePayment(input) { return { data: input.data }; }

async cancelPayment(input) { return { data: input.data }; }

async refundPayment({ data, amount }) {

await fetch('https://api.wave.com/v1/refunds', {

method: 'POST',

headers: {

'Authorization': Bearer ${process.env.WAVE_API_KEY},

'Idempotency-Key': refund_${data.wave_id}_${amount},

},

body: JSON.stringify({ payment_id: data.wave_id, amount: String(amount) }),

Besoin d'un site web professionnel ?

Kolonell crée des sites web qui attirent des clients, optimisés pour le marché sénégalais. Devis gratuit en 2 minutes.

});

return { data };

}

}

export default WavePaymentProvider;

`

Étape 3 — MTN MoMo Provider (Anglophone Africa)

MTN MoMo couvre Ghana, Côte d'Ivoire, Cameroun, Ouganda, Rwanda, Zambie, Bénin :

`ts

// src/modules/mtn-momo-payment/service.ts

class MtnMomoProvider extends AbstractPaymentProvider {

static identifier = 'mtn-momo';

async initiatePayment({ amount, currency_code, data }) {

const apiUserId = process.env.MTN_API_USER_ID;

const apiKey = process.env.MTN_API_KEY;

const subKey = process.env.MTN_SUB_KEY;

// 1. Get OAuth token

const tokenRes = await fetch('https://sandbox.momodeveloper.mtn.com/collection/token/', {

method: 'POST',

headers: {

'Authorization': Basic ${Buffer.from(${apiUserId}:${apiKey}).toString('base64')},

'Ocp-Apim-Subscription-Key': subKey,

},

});

const { access_token } = await tokenRes.json();

// 2. Request to pay

const referenceId = crypto.randomUUID();

await fetch('https://sandbox.momodeveloper.mtn.com/collection/v1_0/requesttopay', {

method: 'POST',

headers: {

'Authorization': Bearer ${access_token},

'X-Reference-Id': referenceId,

'X-Target-Environment': 'sandbox',

'Ocp-Apim-Subscription-Key': subKey,

'Content-Type': 'application/json',

},

body: JSON.stringify({

amount: String(amount),

currency: currency_code.toUpperCase(),

externalId: data.cart_id,

payer: { partyIdType: 'MSISDN', partyId: data.payer_msisdn },

payerMessage: 'Order ' + data.cart_id,

payeeNote: 'Kolonell store',

}),

});

return { data: { mtn_reference: referenceId } };

}

async authorizePayment({ data }) {

// Poll status

const tokenRes = await fetch('https://sandbox.momodeveloper.mtn.com/collection/token/', { /* ... */ });

const { access_token } = await tokenRes.json();

const statusRes = await fetch(

https://sandbox.momodeveloper.mtn.com/collection/v1_0/requesttopay/${data.mtn_reference},

{ headers: { 'Authorization': Bearer ${access_token}, 'X-Target-Environment': 'sandbox' } }

);

const status = await statusRes.json();

return { status: status.status === 'SUCCESSFUL' ? 'authorized' : 'pending', data: status };

}

}

`

Étape 4 — frontend Next.js storefront

Medusa fournit un starter Next.js. Adaptez le composant Checkout pour proposer le bon provider selon le pays détecté :

`tsx

// app/checkout/payment-method.tsx

const providers = useMemo(() => {

switch (cart.region.country_code) {

case 'sn':

case 'ci': return ['wave', 'orange-money', 'paydunya'];

case 'gh': return ['mtn-momo', 'vodafone-cash', 'paystack'];

case 'ng': return ['paystack', 'flutterwave'];

case 'ke':

case 'tz': return ['mpesa', 'stripe'];

case 'cm': return ['orange-money', 'mtn-momo', 'express-union'];

default: return ['stripe'];

}

}, [cart.region.country_code]);

`

Étape 5 — déploiement & coût mensuel

ComposantServiceCoût/mois
Medusa backendHetzner Cloud CX21 (4 vCPU, 8 GB)8 €
PostgresNeon Pro (5 GB)19 €
RedisUpstash Free → Pay (faible volume)0-5 €
Storefront Next.jsVercel Hobby ou Cloudflare Pages0-20 €
CDN imagesCloudflare R25-15 €
Domaine + DNSCloudflare1 €
Total33-68 €/mois

À comparer à Shopify Basic (29 €/mois) + 2 % transaction si paiement non-Shopify Payments sur volume 50M FCFA = ~840 €/mois extra.

Pièges connus

  • Medusa v2 vs v1 : la v2 (sortie fin 2024) refactore les modules. Tutoriels v1 obsolètes — toujours vérifier la version doc.
  • Migrations Postgres : Medusa génère les schémas, mais en pan-africain multi-devise, vérifier le scaling sur prices table.
  • Performance images : Cloudinary > Cloudflare Images si vous voulez les transformations à la volée.
  • Sandbox MTN MoMo : très instable, prévoir un fallback fixture local pour les tests CI.

FAQ

Q : Medusa fonctionne avec Vercel ?

R : Le storefront Next.js oui (Edge runtime). Le backend Medusa nécessite Node long-running → préférer Hetzner, Railway, Render ou Fly.io.

Q : Multi-devise XOF + NGN + KES dans la même boutique ?

R : Oui via les Regions de Medusa. Chaque region = devise + pays + providers.

Q : Combien d'heures pour la stack complète ?

R : ~14 jours-développeur (1 dev senior). 2 jours setup + auth, 5 jours providers paiement, 4 jours storefront + checkout, 3 jours admin & tests.

Conclusion

Medusa devient en 2026 le choix pragmatique pour les e-commerces panafricains qui veulent garder le contrôle, payer 8x moins de fees, et brancher 5+ passerelles locales. Le ticket d'entrée technique est plus haut que Shopify, mais le ROI à 6 mois est sans appel sur les volumes > 30M FCFA/mois.

Tags :#Medusa#Headless Commerce#Wave#MTN MoMo#Pan-Afrique#Open-Source
Partager :

Mohamed Bah

Fondateur, Kolonell

Passionné par le digital et l'entrepreneuriat en Afrique, Mohamed accompagne les entreprises sénégalaises dans leur transformation digitale depuis 2020. Fondateur de Kolonell, il croit que chaque PME mérite une présence en ligne professionnelle et accessible.