DEV Community

Cover image for How to Send Bulk SMS in Uganda with PHP (MTN MoMo Top-Up, No VISA Card Needed)
yoola sms
yoola sms

Posted on

How to Send Bulk SMS in Uganda with PHP (MTN MoMo Top-Up, No VISA Card Needed)

How to Send Bulk SMS in Uganda with PHP (MTN MoMo Top-Up, No VISA Card Needed)

If you've ever tried to integrate SMS into a Ugandan app, you've hit the same wall every developer here hits:

  • Twilio wants a VISA card your client doesn't have
  • International APIs charge in USD with no Mobile Money option
  • Local options are either expensive, poorly documented, or both

I spent months dealing with this before building Yoola SMS — a bulk SMS API designed specifically for Uganda and East Africa. You top up with MTN Mobile Money or Airtel Money. No VISA. No USD. Prices start at UGX 35/SMS dropping to UGX 20 at volume.

Here's how to integrate it today.


Step 1: Get Your Free Account and API Key

Go to yoolasms.com/accounts/register — 60 seconds, no credit card. You get 3 free SMS to test immediately.

Once in, go to My API Key and copy your key.


Step 2: Top Up With Mobile Money

Click Top Up Credits in your dashboard. Enter your MTN MoMo or Airtel Money number. You get a payment prompt on your phone. Approve it. Credits appear instantly.

UGX 10,000 = 285 credits at the Basic rate. Each credit = 1 SMS.


Step 3: Send Your First SMS in PHP

<?php

function yoolaSend($phone, $message, $apiKey, $sender = 'YoolaSMS') {
    $ch = curl_init('https://yoolasms.com/api/v1/send.php');
    curl_setopt_array($ch, [
        CURLOPT_POST           => true,
        CURLOPT_POSTFIELDS     => json_encode([
            'phone'   => $phone,
            'message' => $message,
            'api_key' => $apiKey,
            'sender'  => $sender,
        ]),
        CURLOPT_HTTPHEADER     => ['Content-Type: application/json'],
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT        => 30,
    ]);
    $result = json_decode(curl_exec($ch), true);
    curl_close($ch);
    return $result;
}

$apiKey = 'YOUR_API_KEY_HERE';

// Single SMS
$r = yoolaSend('0704487563', 'Hello! Your order is confirmed. Thank you.', $apiKey, 'MyShop');
echo "Sent: {$r['status']} | Credits used: {$r['credits_used']} | Balance: {$r['balance']}\n";

// Bulk SMS — comma-separate numbers
$phones = '0704487563,0772727716,0756111222,0701333444';
$r = yoolaSend($phones, 'Dear customer, Term 2 fees are due Friday. Pay via MoMo to 0704484563.', $apiKey, 'SchoolSMS');
echo "Bulk sent to {$r['recipients']} people. Credits used: {$r['credits_used']}\n";
Enter fullscreen mode Exit fullscreen mode

That is it. No SDK to install. No npm package. Just cURL.


Real Example: Automated Fee Reminders for a School

This is one of the most common use cases in Uganda. Here is a complete script:

<?php
// fee_reminders.php — add to cron: 0 8 * * 1 (runs every Monday at 8AM)

require 'db.php'; // your database connection
$API_KEY  = 'YOUR_API_KEY';
$due_date = date('j F Y', strtotime('+7 days'));

$students = $pdo->query("
    SELECT s.parent_phone, s.student_name, f.balance_due
    FROM students s
    JOIN fees f ON f.student_id = s.id
    WHERE f.balance_due > 0 AND f.term = 'Term2'
")->fetchAll();

foreach ($students as $s) {
    $msg = "Dear Parent, {$s['student_name']}'s fees balance of UGX "
         . number_format($s['balance_due'])
         . " is due {$due_date}. Pay via MTN MoMo to 0704484563. Thank you.";

    $result = yoolaSend($s['parent_phone'], $msg, $API_KEY, 'SchoolSMS');

    if ($result['status'] !== 'success') {
        error_log("SMS failed: {$s['parent_phone']}{$result['message']}");
    }
    usleep(100000); // 0.1s pause between sends
}
echo "Fee reminders sent.\n";
Enter fullscreen mode Exit fullscreen mode

Set this as a cron job. Your bursar never chases parents manually again.


Handling Errors Properly

$result = yoolaSend($phone, $message, $apiKey);

match($result['status']) {
    'success'          => handleSuccess($result),
    'insufficient_fund'=> notifyAccountOwner('Low SMS credits! Top up now.'),
    'invalidkey'       => throw new Exception('Check your Yoola SMS API key'),
    'missing'          => throw new Exception('Phone or message field is empty'),
    default            => retryAfterDelay(3),
};
Enter fullscreen mode Exit fullscreen mode

Sending to East Africa and International

Same API, same code — just use international format:

// Uganda — 1 credit
yoolaSend('0704487563', $msg, $apiKey);

// Kenya — 3 credits
yoolaSend('+254712345678', $msg, $apiKey);

// Tanzania — 3 credits  
yoolaSend('+255756123456', $msg, $apiKey);

// UK Diaspora — 12 credits
yoolaSend('+447384014597', $msg, $apiKey);

// Mix Uganda + Kenya in one bulk call — credits calculated per number
$phones = '0704487563,+254712345678,0772727716';
yoolaSend($phones, $msg, $apiKey);
Enter fullscreen mode Exit fullscreen mode

Check Balance Anytime

$balance = json_decode(file_get_contents(
    'https://yoolasms.com/api/v1/balance.php?api_key=' . $apiKey
), true);

echo "Credits: {$balance['balance']}\n";
echo "UGX value: {$balance['amount']}\n";
Enter fullscreen mode Exit fullscreen mode

The API Response Object

{
    "status": "success",
    "code": 200,
    "message": "SMS sent successfully",
    "recipients": 4,
    "credits_used": 4,
    "balance": 281,
    "message_parts": 1
}
Enter fullscreen mode Exit fullscreen mode

message_parts tells you if your message was split (over 160 characters = multiple parts = multiple credits per recipient). Keep messages under 160 characters for best value.


Get Started

🔗 Create free account — 3 SMS free, no card

📖 Full API docs

💬 Community Q&A — ask anything

📞 WhatsApp support: +256 704 484 563

Built in Uganda 🇺🇬 — works across East Africa and 40+ countries worldwide.


Drop your questions in the comments — I reply to every one.

php #uganda #africa #sms #api #webdev #tutorial

Top comments (0)