McTaba Labs logo
Software EngineeringThe WhiteboardProjectsEventsMasterclassesWebinarsLearn
Book Call

500+ developers already in the community

Get answers, find accountability partners, and stay ahead

Join Discord →
McTaba Labs logo

Educating 1 million students in tech by 2030.

Programs

  • HighSchool Graduates Launchpad
  • AI & Business Automation
  • Corporate Training
  • McTaba Story & Mission
  • Full-Stack Curriculum
  • Course Pricing & Plans
  • Frequently Asked Questions

Resources

  • Join Discord Community
  • Tech Events in Nairobi
  • Masterclasses
  • Free Resources
  • Learn
  • Campus
  • Africa Tech Talent Report
  • Partner With Us
  • Start a Project
  • Our Work

Contact Us

  • 124 Manyani East Road, Lavington, Nairobi
  • +254727795603
  • Book a Discovery Call

Office Hours:

Mon-Fri: 9am - 2pm EAT

Sat: 10am - 12pm EAT

© 2027 McTaba Labs - A product of Edtech Industries. All rights reserved.

Privacy PolicyTerms of ServiceRefund Policy
  1. Learn
  2. Paystack for African Developers
  3. Accepting Mobile Money Payments Through Paystack
Bonaventure OgetoBy Bonaventure Ogeto|Updated July 20, 2026

Accepting Mobile Money Payments Through Paystack

To accept mobile money through Paystack, initialize a GHS transaction with the mobile_money channel enabled. Via hosted checkout, the customer selects mobile money and enters their phone number. Via the Charge API, POST to /charge with a mobile_money object containing the phone and provider. The customer receives an approval prompt on their phone. Once approved, Paystack fires a charge.success webhook.

In this article

  1. 1. How Mobile Money Works on Paystack
  2. 2. Mobile Money via Hosted Checkout
  3. 3. Mobile Money via the Charge API
  4. 4. Handling the Approval Wait
  5. 5. Timeout and Failure Handling
  6. 6. Amount Handling for Mobile Money
  7. 7. Stay Up to Date

How Mobile Money Works on Paystack

Mobile money payments follow an asynchronous approval pattern:

  1. The customer provides their mobile money phone number and selects their provider (MTN, AirtelTigo, or Vodafone)
  2. Paystack sends a payment request to the mobile money provider
  3. The provider sends an authorization prompt to the customer's phone (an STK push or USSD prompt)
  4. The customer enters their mobile money PIN on their phone to approve
  5. The provider deducts the funds and notifies Paystack
  6. Paystack fires a charge.success webhook to your server

The key difference from card payments: between step 2 and step 5, you are waiting for the customer to act on a separate device. This can take seconds or minutes. Your checkout UI needs to show a waiting state during this period.

Mobile Money via Hosted Checkout

The simplest approach. Initialize a GHS transaction with the mobile_money channel:

var response = await fetch('https://api.paystack.co/transaction/initialize', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    email: 'customer@example.com',
    amount: 5000, // 50 GHS in pesewas
    currency: 'GHS',
    channels: ['mobile_money'], // or ['card', 'mobile_money'] for both
    callback_url: 'https://yoursite.com/payment/callback',
  }),
});

var data = await response.json();
// Redirect to data.data.authorization_url or use the access_code

Paystack's checkout page handles the phone number input, provider selection, and the waiting screen while the customer approves on their phone. You do not need to build any of this UI.

Get weekly developer tips

Join 25,000+ developers. Practical guides, job tips, and new content — straight to your inbox.

No spam. Unsubscribe anytime.

Mobile Money via the Charge API

For a custom checkout where you collect the phone number and provider in your own UI:

async function chargeMobileMoney(email, amount, phone, provider) {
  var response = await fetch('https://api.paystack.co/charge', {
    method: 'POST',
    headers: {
      Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      email: email,
      amount: amount,
      currency: 'GHS',
      mobile_money: {
        phone: phone,       // e.g., '0241234567'
        provider: provider,  // 'mtn', 'atl', or 'vod'
      },
    }),
  });

  var data = await response.json();

  if (data.data.status === 'send_otp') {
    // Customer needs to approve on their phone
    return { status: 'pending_approval', reference: data.data.reference };
  }

  if (data.data.status === 'success') {
    return { status: 'success', reference: data.data.reference };
  }

  return { status: 'failed', message: data.data.gateway_response };
}

// Usage
var result = await chargeMobileMoney(
  'customer@example.com',
  5000, // 50 GHS
  '0241234567',
  'mtn'
);

if (result.status === 'pending_approval') {
  // Show: "Check your phone and approve the payment"
  // Wait for webhook to confirm
}

Provider codes: mtn (MTN MoMo), atl (AirtelTigo), vod (Vodafone Cash).

Handling the Approval Wait

After the charge is initiated, the customer needs to approve on their phone. This creates a user experience challenge: how long do you wait, and what do you show?

// Frontend: show waiting state and poll for completion
async function waitForApproval(reference, maxWaitSeconds) {
  var startTime = Date.now();
  var maxWait = (maxWaitSeconds || 120) * 1000; // Default 2 minutes

  while (Date.now() - startTime < maxWait) {
    var response = await fetch('/api/check-payment?reference=' + reference);
    var data = await response.json();

    if (data.status === 'success') {
      return { paid: true };
    }

    if (data.status === 'failed') {
      return { paid: false, reason: data.reason };
    }

    // Wait 5 seconds before checking again
    await new Promise(function(resolve) { setTimeout(resolve, 5000); });
  }

  return { paid: false, reason: 'timeout' };
}

Better approach: instead of polling, use a webhook to update your database, and have the frontend poll your database. This way you get the definitive confirmation from Paystack via webhook, not from a verify call that might miss timing.

Show a clear message while waiting: "A payment prompt has been sent to 024****567. Open your phone and enter your mobile money PIN to approve." Include a countdown timer or a loading indicator so the customer knows something is happening.

Timeout and Failure Handling

Mobile money prompts expire after a timeout period set by the provider (typically 1-2 minutes). If the customer does not approve within that window, the charge fails.

Common failure reasons:

  • Insufficient funds: The customer does not have enough money in their mobile money wallet
  • Wrong PIN: The customer entered the wrong PIN when approving
  • Timeout: The customer did not respond to the prompt in time
  • Phone off: The customer's phone was off or unreachable when the prompt was sent
  • Wrong number: The phone number provided does not have a mobile money account

When a mobile money charge fails, give the customer the option to try again or switch to a different payment method (card). Do not force them to restart the entire checkout process.

Amount Handling for Mobile Money

Mobile money transactions use GHS (Ghanaian Cedi) with amounts in pesewas. The conversion is the same as other currencies: multiply the display amount by 100.

// 50 GHS = 5000 pesewas
var amountInPesewas = Math.round(50 * 100); // 5000

// Mobile money providers may have minimum and maximum transaction limits
// These limits vary by provider and account type
// Check Paystack documentation for current limits

Mobile money wallets have balance limits that are lower than bank account limits. A customer might have enough for a 500 GHS purchase on their debit card but not in their mobile money wallet. For high-value transactions, offering card as an alternative is important.

For more on amount handling, see kobo, pesewa, and cents explained.

Stay Up to Date

Mobile money integration details on Paystack evolve as providers update their APIs and Paystack adds new features.

Sign up for the McTaba newsletter to get notified about Paystack mobile money updates.

Key Takeaways

  • ✓Mobile money on Paystack is available for GHS (Ghanaian Cedi) transactions. You need a Ghana-registered Paystack account.
  • ✓Supported providers: MTN Mobile Money (MoMo), AirtelTigo Money, and Vodafone Cash.
  • ✓The customer enters their mobile money number and receives a prompt on their phone to authorize the payment.
  • ✓Mobile money is asynchronous. There is a gap between the prompt being sent and the customer approving. Handle this wait time in your UI.
  • ✓Via hosted checkout, Paystack manages the entire flow. Via the Charge API, you send the phone and provider and handle the pending status.
  • ✓Always confirm via webhook, not by polling. The charge.success event is the reliable signal that payment was received.

Frequently Asked Questions

Can I accept mobile money payments in Nigeria?
Mobile money on Paystack is currently available for GHS (Ghana) transactions. For Nigerian payments, the equivalent channels are bank transfer, USSD, and card. The mobile money landscape in Nigeria is evolving, so check Paystack for current availability.
What phone number format does Paystack expect?
Paystack accepts Ghanaian phone numbers in local format (e.g., 0241234567) or international format (e.g., 233241234567). Validate the phone number on your end before sending to Paystack to provide better error messages to customers.
Can the customer approve mobile money on a different phone?
No. The approval prompt is sent to the phone number associated with the mobile money account. The customer must approve on that specific phone. They cannot approve on a different device.
Do mobile money refunds work like card refunds?
Yes. You can refund mobile money transactions via the Paystack refund endpoint. The refund goes back to the customer mobile money wallet. Processing time may vary by provider.
Is mobile money available for recurring payments?
Mobile money does not support saved authorization codes the way cards do. Each payment requires the customer to approve on their phone. For recurring mobile money collections, you would need to send a new charge each billing period and have the customer approve each time.

Learn Paystack Integration

KES 2,999

The definitive guide to building payment systems with Paystack — from your first transaction to production-grade payment infrastructure across Africa. 9 modules, 47 lessons. Free preview available.

Start Paystack Course

Not ready? Create Free Account

Keep reading

Accepting Payments with Paystack: Complete Guide

Everything you need to accept your first payment with Paystack: choosing between Initialize Transaction and the Charge API, handling amounts in kobo, attaching metadata, setting callback URLs, and designing transaction references that keep your system clean.

Read more

Paystack Metadata: Passing Custom Data Through a Transaction

Paystack metadata lets you attach arbitrary JSON data to a transaction that flows through the entire lifecycle: from initialization to verification to webhooks. This guide shows you what to put in metadata, how to structure it for different use cases, and the limits you need to stay within.

Read more

Paystack Product API for Simple Storefronts

The Paystack Product API lets you create products with names, prices, and descriptions, then generate payment links for each one. For simple storefronts selling a handful of products, this is faster than building a full e-commerce backend. This guide covers creating products, linking them to payment pages, and knowing when to outgrow this approach.

Read more

Building a Wallet Top-Up Flow on Paystack

A step-by-step guide to building wallet top-up flows with Paystack. Initialize payment, handle webhooks, credit wallets safely, enforce minimum amounts, and prevent double-crediting in production.

Read more

Queueing Paystack Webhook Work with BullMQ

Process Paystack webhooks with BullMQ and Redis so your endpoint returns 200 instantly while heavy work happens in a background worker. Covers Express handler, job creation, worker setup, retries, and monitoring.

Read more

Explore related topics

M-Pesa & African Stack

M-Pesa Daraja API tutorials, USSD development, and WhatsApp Business API guides. The African Stack that global bootcamps do not teach.

Learn to Code in Kenya

Everything a Kenyan needs to know before writing their first line of code. Career paths, real costs, hardware requirements, and honest answers about what it takes.

Learning to Code

Roadmaps, language guides, and practical advice for learning to code and launching a programming career.

Breaking Into Tech

Practical, no-nonsense guides for anyone looking to start or change their career in tech. From choosing your first language to acing interviews.

The African Stack: Skills for This Market

The skills that make Kenyan developers hard to replace: M-Pesa, USSD, WhatsApp, fintech, and building for the African market.

Bonaventure Ogeto

Bonaventure Ogeto

Founder, McTaba Labs

Bonaventure is the founder of McTaba Labs, a coding bootcamp in Nairobi, Kenya. He has spent years building products for the African market and mentoring the next generation of developers across the continent.