Building a USSD Payment Solution with PHP, MySQL, Redis and Paystack

What is USSD?

Unstructured Supplementary Service Data (USSD), sometimes referred to as "quick codes" or "feature codes", is a communications protocol used by GSM cellular telephones to communicate with the mobile network operator's computers. USSD can be used for WAP browsing, prepaid callback service, mobile-money services, location-based content services, menu-based information services, and as part of configuring the phone on the network.

USSD is an old technology mainly used in Africa. The continent has about 18% Internet penetration but over 80% mobile penetration. This 80% that are connected on mobile represent over 960 million people who have phones.

These people have real lives and real problems, and software developers can build apps to solve these problems. USSD-run applications are easily accessible by people with both smartphones as well as basic and feature phones, therefore reaching a wider audience than smartphone apps.

Why I chose the tech stack to build this app

I chose to use PHP mainly because USSD is an old technology and PHP, being an old language compared to Node.js for the backend, has robust community support and better integration with third-party platforms.

Business Model

The app is targeted at low income earners such as market women, salespeople, and cab drivers. The concept is that they can purchase vouchers of the desired amount they want to save from designated vendors, dial the code and follow the simple process (it's as simple as recharging a card), then the money is deposited into the recipient's account.

Getting Started

To get started you will need the following installed on your PC:

  • Install XAMPP on your machine. It installs PHP and MySQL on your machine.
  • Install Redis for caching.
  • Create a free account on Paystack.
  • Download Postman for testing.

Building the Index.php File

We want to first include a menu.php and user.php file which will be created later. Then pull out the session-id, service-code, phone-number and USSD code from the post request. The syntax checks if the user is registered or not (we would still add a function that checks if a user is registered on the database and returns the user name if registered). I used a switch statement that checks the code pressed on the phone and executes the statements associated with that case.

<?php
 
include_once "menu.php";
include_once "user.php";
 
$sessionId = $_POST["sessionId"];
$serviceCode = $_POST["serviceCode"];
$phoneNumber = $_POST["phoneNumber"];
$text = $_POST["text"];
 
if ($text === "" && $user->isUserRegistered()) {
    echo " CON " . $menu->mainMenuRegistered();
} else if ($text == ""  && !$user->isUserRegistered()) {
    $menu->mainMenuUnRegistered();
} else if (!$user->isUserRegistered()) {
    $textArray = explode("*", $text);
    switch ($textArray[0]) {
        case 1:
            $menu->registerMenu($textArray, $phoneNumber);
            break;
        default:
            echo "END Invalid choice. Please try again";
    };
} else {
    // user is registered but string is not empty
    $textArray = explode("*", $text);
    switch ($textArray[0]) {
        case 1:
            $menu->sendMoneyMenu($textArray);
            break;
        case 2:
            $menu->withdrawMoneyMenu($textArray);
            break;
        case 3:
            $menu->checkBalanceMenu($textArray);
            break;
        default:
            echo "CON Invalid menu\n" . $menu->mainMenuRegistered();
    };
};

Building the Menu Page

The menu consists of two main menus for two types of users:

  • Registered users
  • Unregistered users

Then the sub-menus include:

  • Register (for unregistered users)
  • Send money
  • Withdraw
  • Check balance
<?php
 
class Menu
{
    protected $text;
    protected $sessionID;
 
    function __construct()
    {
    }
 
    public function mainMenuRegistered()
    {
    }
 
    public function mainMenuUnRegistered()
    {
    }
 
    public function registerMenu()
    {
    }
 
    public function sendMoneyMenu($textArray)
    {
    }
 
    public function withdrawMoneyMenu($textArray)
    {
    }
 
    public function checkBalanceMenu($textArray)
    {
    }
}