Back to 0fee
0fee

The Africa Payment Problem: Why Stripe Is Not Enough

Africa's $1T+ mobile money market needs more than Stripe. How 0fee.dev solves the Africa payment problem. By Juste A. Gnimavo and Claude.

Thales & Claude | March 25, 2026 10 min 0fee
africamobile-moneypaymentsfintechmtn-momoorange-money

Africa processes over $1 trillion in mobile money transactions annually. More than 500 million people use mobile money as their primary financial instrument -- not as an alternative to cards, but as a replacement for an entire banking system that never reached them. Yet if you try to accept a payment from a customer in Ivory Coast, Senegal, or Cameroon using Stripe, you will discover that the world's most popular payment platform simply does not work for most of the continent.

This is the Africa payment problem. And it is the single biggest reason we built 0fee.dev.

The Numbers That Change Everything

Consider these figures from the GSMA's State of the Industry Report:

MetricValue
Registered mobile money accounts (Africa)850+ million
Active mobile money accounts (monthly)400+ million
Annual transaction value$1 trillion+
Mobile money agents across Africa10+ million
Card penetration (Sub-Saharan Africa)< 5%
Bank account penetration (Sub-Saharan Africa)~30%
Mobile phone penetration (Sub-Saharan Africa)~85%

The contrast is stark. In the United States, 80%+ of adults have a credit or debit card. In Sub-Saharan Africa, fewer than 5% do. But 85% have a mobile phone, and nearly half of all adults have an active mobile money account. The payment infrastructure is not absent -- it is just fundamentally different.

How Mobile Money Works

For readers unfamiliar with mobile money, here is the flow. It has nothing in common with card payments.

The Customer Experience

  1. The customer selects "Pay with Orange Money" (or MTN MoMo, Wave, M-Pesa, etc.).
  2. They enter their phone number.
  3. They receive a USSD push or STK push notification on their phone -- a simple menu on their screen, not an app notification.
  4. They enter their PIN to confirm the payment.
  5. The transaction settles. Both parties receive an SMS confirmation.

There is no card number, no CVV, no 3D Secure, no billing address. The entire authentication is phone number + PIN. The "account" is the SIM card itself.

The Technical Flow

From an integration perspective, mobile money is asynchronous by nature:

1. Merchant -> Provider API: initiate payment (phone, amount)
2. Provider -> Telco: send USSD/STK push to customer
3. Customer -> Phone: enter PIN to confirm
4. Telco -> Provider: confirmation callback
5. Provider -> Merchant: webhook notification (success/failure)

This means your integration must handle:

  • Asynchronous confirmation: the customer might take 30 seconds or 5 minutes to confirm.
  • Timeout handling: if the customer does not respond, the transaction expires (typically 60-120 seconds for USSD).
  • Phone number validation: each country has specific formats (+225 07XXXXXXXX for Ivory Coast, +233 XX XXX XXXX for Ghana).
  • USSD session limits: some telcos limit concurrent USSD sessions per phone number.

The Provider Landscape

No single provider covers all of Africa. Each provider has its own geographic footprint, supported payment methods, and technical integration:

East Africa

ProviderCountriesMethodsIntegration
PawaPayKenya, Tanzania, Uganda, Rwanda, DRC, Mozambique, Zambia, MalawiM-Pesa, MTN MoMo, Airtel Money, Tigo PesaREST API, webhooks
Safaricom (direct)KenyaM-Pesa onlyDaraja API, STK Push
FlutterwaveKenya, Tanzania, Uganda, RwandaM-Pesa, cards, bank transferREST API

West Africa (Francophone)

ProviderCountriesMethodsIntegration
Hub2Ivory Coast, Senegal, Mali, Burkina Faso, Togo, Benin, Guinea, CameroonOrange Money, MTN MoMo, Moov Money, WaveREST API, callbacks
PaiementProIvory Coast, Senegal, Burkina Faso, Togo, BeninOrange Money, MTN MoMo, Moov Money, Visa/MastercardREST API
BUIIvory Coast, Senegal, Mali, Burkina FasoMobile money, cardsREST API

West Africa (Anglophone)

ProviderCountriesMethodsIntegration
PaystackNigeria, Ghana, South Africa, KenyaCards, bank transfer, USSD, mobile moneyREST API
FlutterwaveNigeria, Ghana + 28 othersCards, bank transfer, mobile money, USSDREST API

Pan-African

ProviderCountriesMethodsIntegration
PawaPay21+ African countriesMobile money (all major wallets)REST API
Flutterwave30+ African countriesCards, mobile money, bank transfersREST API
Cellulant (Tingg)35+ African countriesMobile money, cards, bank transfersREST API

To accept payments across Africa, you need at minimum three to four provider integrations -- and likely more if you want optimal coverage and redundancy.

The 0fee Solution

0fee abstracts all of this complexity behind a unified API. Every mobile money payment method in every country follows the same request/response format:

typescriptimport { ZeroFee } from 'zerofee';

const zf = new ZeroFee({ apiKey: 'zf_live_...' });

// Orange Money in Ivory Coast
const paymentCI = await zf.payments.create({
  amount: 5000,           // 5,000 XOF
  currency: 'XOF',
  country: 'CI',
  method: 'PAYIN_ORANGE_CI',
  customer: { phone: '+2250700112233' },
  returnUrl: 'https://yourapp.com/callback'
});

// MTN MoMo in Ghana
const paymentGH = await zf.payments.create({
  amount: 50_00,          // 50.00 GHS in cents
  currency: 'GHS',
  country: 'GH',
  method: 'PAYIN_MTN_GH',
  customer: { phone: '+233241234567' },
  returnUrl: 'https://yourapp.com/callback'
});

// M-Pesa in Kenya
const paymentKE = await zf.payments.create({
  amount: 1000_00,        // 1,000.00 KES in cents
  currency: 'KES',
  country: 'KE',
  method: 'PAYIN_MPESA_KE',
  customer: { phone: '+254712345678' },
  returnUrl: 'https://yourapp.com/callback'
});

Three different countries, three different mobile money providers, three different telcos -- but identical code structure. The routing engine determines which underlying provider to use based on country, method, and configured credentials.

Payment Method Naming Convention

We designed a systematic naming convention for every payment method in the system:

{DIRECTION}_{METHOD}_{COUNTRY}

PAYIN_ORANGE_CI    = Pay in via Orange Money in Ivory Coast
PAYIN_MTN_GH       = Pay in via MTN MoMo in Ghana
PAYIN_MPESA_KE     = Pay in via M-Pesa in Kenya
PAYIN_WAVE_SN      = Pay in via Wave in Senegal
PAYIN_CARD_US      = Pay in via card in the United States
PAYOUT_ORANGE_CI   = Pay out to Orange Money in Ivory Coast
PAYOUT_BANK_NG     = Pay out to bank account in Nigeria

This convention makes the API self-documenting. A developer can immediately understand what PAYIN_AIRTEL_UG means without reading documentation: it is a pay-in via Airtel Money in Uganda.

The complete list of African mobile money methods in 0fee:

Method CodeProviderCountry
PAYIN_ORANGE_CIOrange MoneyIvory Coast
PAYIN_ORANGE_SNOrange MoneySenegal
PAYIN_ORANGE_MLOrange MoneyMali
PAYIN_ORANGE_BFOrange MoneyBurkina Faso
PAYIN_ORANGE_CMOrange MoneyCameroon
PAYIN_MTN_GHMTN MoMoGhana
PAYIN_MTN_CMMTN MoMoCameroon
PAYIN_MTN_UGMTN MoMoUganda
PAYIN_MTN_CIMTN MoMoIvory Coast
PAYIN_MTN_BJMTN MoMoBenin
PAYIN_MPESA_KEM-PesaKenya
PAYIN_MPESA_TZM-PesaTanzania
PAYIN_WAVE_SNWaveSenegal
PAYIN_WAVE_CIWaveIvory Coast
PAYIN_MOOV_CIMoov MoneyIvory Coast
PAYIN_MOOV_BJMoov MoneyBenin
PAYIN_MOOV_TGMoov MoneyTogo
PAYIN_AIRTEL_UGAirtel MoneyUganda
PAYIN_AIRTEL_TZAirtel MoneyTanzania
PAYIN_AIRTEL_KEAirtel MoneyKenya
PAYIN_TIGO_TZTigo PesaTanzania
PAYIN_VODACOM_TZVodacom M-PesaTanzania
PAYIN_VODACOM_MZVodacom M-PesaMozambique

And this is just a subset. The full catalog includes 117 payment methods across Africa, Europe, North America, South America, and Asia.

The Webhook Problem

One of the most painful aspects of multi-provider integration is webhook handling. Each provider sends callbacks in a different format:

PawaPay webhook: ``json { "depositId": "dep_abc123", "status": "COMPLETED", "amount": "1000", "currency": "KES", "correspondent": "MPESA_KEN" } ``

Hub2 callback: ``json { "transaction_id": "txn_xyz789", "statut": "SUCCESS", "montant": 5000, "devise": "XOF", "operateur": "ORANGE_MONEY" } ``

Paystack webhook: ``json { "event": "charge.success", "data": { "id": 123456, "status": "success", "amount": 50000, "currency": "NGN", "channel": "mobile_money" } } ``

Three different providers, three different field names, three different status values, three different amount formats. In a direct integration, you would write three separate webhook handlers with three separate validation and normalization pipelines.

0fee normalizes all of this. Your application receives one standardized webhook format regardless of which provider processed the payment:

json{
  "event": "payment.completed",
  "data": {
    "id": "pay_0fee_abc123",
    "status": "completed",
    "amount": 5000,
    "currency": "XOF",
    "country": "CI",
    "method": "PAYIN_ORANGE_CI",
    "provider": "hub2",
    "customer": {
      "phone": "+2250700112233"
    },
    "metadata": {},
    "created_at": "2026-03-27T10:30:00Z",
    "completed_at": "2026-03-27T10:30:45Z"
  }
}

One webhook handler. One status enum. One amount format. Every provider normalized to the same contract.

OTP and USSD: Authentication Without Cards

Card payments use a well-understood authentication model: card number, expiry, CVV, and optionally 3D Secure. Mobile money authentication is entirely different and varies by telco and country.

USSD Push (most common in West Africa): The provider sends a USSD prompt to the customer's phone. The customer sees a text-based menu: "Pay 5,000 XOF to [Merchant]? Enter PIN:" -- this happens at the SIM/telco level, not within an app.

STK Push (M-Pesa, East Africa): The SIM Toolkit triggers a payment prompt directly on the phone. The customer sees a pop-up asking them to confirm the amount and enter their M-Pesa PIN.

OTP via SMS (some providers): The customer receives an SMS with a one-time code, which they enter on the merchant's checkout page. This is closer to 3D Secure but uses SMS instead of a bank's authentication page.

Each of these flows has different timeout characteristics, different retry semantics, and different failure modes. 0fee handles all of them behind the same asynchronous payment flow: create the payment, wait for the webhook, process the result.

Why This Matters for African Developers

If you are building a product for African users, payments should not be the hardest part of your stack. But today, a developer in Abidjan who wants to accept Orange Money, MTN MoMo, and Wave payments in Ivory Coast alone needs to integrate at least two providers. Add Nigeria and Kenya, and you are looking at four or five integrations.

0fee reduces that to one. Install the SDK, configure your credentials in the dashboard, and your checkout page works across the continent.

bashnpm install zerofee

That is the entire integration prerequisite. One package. One API key. Fifty-three providers. Two hundred countries. Africa included from day one -- not as an afterthought.


This article is part of the "How We Built 0fee.dev" series. 0fee.dev is a payment orchestrator covering 53+ providers across 200+ countries, built by Juste A. GNIMAVO and Claude from Abidjan with zero human engineers. Follow the series for the complete build story.

Share this article:

Responses

Write a response
0/2000
Loading responses...

Related Articles