To use this site please enable javascript on your browser! How to Integrate Mobile Money and Card Payments in Laravel Using Selcom-Tanzania

How to Integrate Mobile Money and Card Payments in Laravel Using Selcom-Tanzania

by Bryce Andy 03:11 Nov 24 '23

Selcom offers a set of Application Programming Interfaces (APIs) that gives you the ability to incorporate Selcom functionality into your projects.

With their cashout API, you have the ability to make payments through mobile money (AirtelMoney, MPesa, TigoPesa, HaloPesa etc), Masterpass, debit/credit cards (MasterCard, VISA, Amex etc).

 

Illustration from selcom.net

To make the developer experience easier for Laravel developers and start using Selcom APIs, we may start by installing the package.

Installation

Before installing the package, make sure you project satisfies the following requirements:

  • Supports Laravel projects starting version 8.*
  • Minimum PHP version is 7.4
  • Your server must have the cURL PHP extension (ext-curl) installed

Then run the following in your project root terminal;

composer require bryceandy/laravel-selcom

Once the package is successfully downloaded, we can start setting up the configuration.

Configuration

To access Selcom's APIs, you will need to provide the package with access to your Selcom vendorID, API Key and Secret Key.

After obtaining the three credentials from Selcom support, add their values in the environment variables .env file;

SELCOM_VENDOR_ID=123456
SELCOM_API_KEY=yourApiKey
SELCOM_API_SECRET=yourSecretKey

SELCOM_IS_LIVE=false

Note that when starting you will be provided with test credentials.

When you change to live credentials don't forget to change SELCOM_IS_LIVE to true.

We are going to update more configuration settings as we move along, but feel free to publish the config to fully customize it;

php artisan vendor:publish --tag=selcom-config

Migration

Run the migration command to create a table that stores Selcom payments;

php artisan migrate

Usage

In this article we are only going to use the checkout API as it's the quickest way to start making payments with Selcom.

The most interesting feature using checkout is the USSD push on mobile money.

Here you can initiate payments on a website or mobile app and Selcom will push the USSD menu on your users phone to confirm a transaction.

Checkout via USSD Push

Support for USSD push at the time of releasing this package (June 2022) was only for TigoPesa and AirtelMoney. To initiate this payment, use the code below;

use Bryceandy\Selcom\Facades\Selcom;

Selcom::checkout([
    'name' => "Buyer's full name", 
    'email' => "Buyer's email",
    'phone' => "Buyer's msisdn, for example 255756334000",
    'amount' => "Amount to be paid",
    'transaction_id' => "Unique transaction id",
    'no_redirection' => true,
    // Optional fields
    'currency' => 'Default is TZS',
    'items' => 'Number of items purchased, default is 1',
    'payment_phone' => 'The number that will make the USSD transactions, if not specified it will use the phone value',
]);

The checkout method above will return a JSON object:

// Sample response
{
  "reference" : "0289999288",
  "resultcode" : "111",
  "result" : "PENDING",
  "message" : "Request in progress. You will receive a callback shortly.",
  "data": []
}

If USSD push isn't yet supported by Selcom for your network, you can make payment directly on Selcom's payment page using the next option below.

Checkout to the payments page (without cards)

The payment page contains payment options such as QR code, Masterpass, USSD wallet pull, mobile money payment with tokens.

To redirect to this page, we will use the previous example, but return without the no_redirection option;

use Bryceandy\Selcom\Facades\Selcom;

return Selcom::checkout([
    'name' => "Buyer's full name", 
    'email' => "Buyer's email",
    'phone' => "Buyer's msisdn, for example 255756334000",
    'amount' => "Amount to be paid",
    'transaction_id' => "Unique transaction id",
]);

Checkout to the payments page (with cards)

To use the cards on the payment page, your route should return the following request;

use Bryceandy\Selcom\Facades\Selcom;

return Selcom::cardCheckout([
    'name' => "Buyer's full name", 
    'email' => "Buyer's email",
    'phone' => "Buyer's msisdn, for example 255756334000",
    'amount' => "Amount to be paid",
    'transaction_id' => "Unique transaction id",
    'address' => "Your buyer's address",
    'postcode' => "Your buyer's postcode",
    // Optional fields
    'user_id' => "Buyer's user ID in your system", // Required if you want the user's cards should be saved for their next visit to the page
    'buyer_uuid' => $buyerUuid, // Required if the user has to see their saved cards. (See below on how to obtain this value)
    'country_code' => "Your buyer's ISO country code: Default is TZ",
    'state' => "Your buyer's state: Default is Dar Es Salaam",
    'city' => "Your buyer's city: Default is Dar Es Salaam",
    'billing_phone' => "Your buyer's billing phone number: forexample 255756334000",
    'currency' => 'Default is TZS',
    'items' => 'Number of items purchased, default is 1',
]);

Obtaining the buyer's UUID

If this user has visited the payment page before to make a payment, then their uuid is already in the database;

use Illuminate\Support\Facades\DB;

$buyerUuid = DB::table('selcom_payments')
    ->where([
        ['user_id', '=' auth()->id()],
        ['gateway_buyer_uuid', '<>', null],
    ])
    ->value('gateway_buyer_uuid');

Customizations & theming

Optionally, you may specify using the .env file the following:

  • The page where your users will be redirected once they complete a payment;
SELCOM_REDIRECT_URL=https://mysite.com/selcom-callback-url
  • The page where your users will be taken when they cancel the payment process;
SELCOM_CANCEL_URL=https://mysite.com/selcom-cancel-url

If you feel lazy, this package already ships with these pages for you. And if you want to customize them, run the following on your terminal;

php artisan vendor:publish --tag=selcom-views

  • Also, you can assign a prefix for the package. This will be applied to the routes and order IDs;
SELCOM_PREFIX=SHOP
  • To customize the colors, add the color values in the .env file;
SELCOM_HEADER_COLOR="#FG345O"
SELCOM_LINK_COLOR="#000000"
SELCOM_BUTTON_COLOR="#E244FF"

For JSON requests (API applications), this type of checkout to the payments page will return data with payment_gateway_url instead of redirecting to that page;

{
  "payment_gateway_url": "https://example.selcommobile-url.com"
}

Checkout payments with cards (without navigating to the payment page)

To use a card without navigating to the payment page, you need to have already created a card for the paying user by navigating to the payment page.

This is very useful for recurring or on-demand card payments. The data is the same as the previous card checkout, except we are adding no_redirection, user_id & buyer_uuid;

use Bryceandy\Selcom\Facades\Selcom;

Selcom::cardCheckout([
    'name' => "Buyer's full name", 
    'email' => "Buyer's email",
    'phone' => "Buyer's msisdn, for example 255756334000",
    'amount' => "Amount to be paid",
    'transaction_id' => "Unique transaction id",
    'no_redirection' => true,
    'user_id' => "Buyer's user ID in your system",
    'buyer_uuid' => $buyerUuid,
    'address' => "Your buyer's address",
    'postcode' => "Your buyer's postcode",
    // Optional fields
    'country_code' => "Your buyer's ISO country code: Default is TZ",
    'state' => "Your buyer's state: Default is Dar Es Salaam",
    'city' => "Your buyer's city: Default is Dar Es Salaam",
    'billing_phone' => "Your buyer's billing phone number: forexample 255756334000",
    'currency' => 'Default is TZS',
    'items' => 'Number of items purchased, default is 1',
]);

This method will fetch 3 saved cards of the user and try all of them until a payment is successful or all fail.

Listing a user's stored cards

To fetch the user's stored cards could be useful to know if a user has cards, or if there is a need to delete.

You will require a user's ID and buyer_uuid;

use Bryceandy\Selcom\Facades\Selcom;

Selcom::fetchCards($userId, $gatewayBuyerUuid);

Deleting a user's stored card

To delete a user's stored card you need a buyer_uuid and card ID obtained from fetchCards request above;

use Bryceandy\Selcom\Facades\Selcom;

Selcom::deleteCard($cardId, $gatewayBuyerUuid);

Checkout webhook/callback

The package comes with an implementation of the payment webhook.

When Selcom sends the payment status to your site, the data in the selcom_payments table will be updated and a Laravel event Bryceandy\Selcom\Events\CheckoutWebhookReceived will be dispatched.

You can create a listener for the event;

class EventServiceProvider extends ServiceProvider
{
    protected $listen = [
        \Bryceandy\Selcom\Events\CheckoutWebhookReceived::class => [
            \App\Listeners\ProcessWebhook::class,
        ],
    ];
}

Then in your listener App\Listeners\ProcessWebhook, you can do anything with the order ID;

<?php

namespace App\Listeners;

use Bryceandy\Selcom\Events\CheckoutWebhookReceived;
use Bryceandy\Selcom\Facades\Selcom;
use Illuminate\Support\Facades\DB;

class ProcessWebhook
{
    /**
     * Handle the event.
     *
     * @param CheckoutWebhookReceived $event
     */
    public function handle(CheckoutWebhookReceived $event)
    {
        // Get the order id
        $orderId = $event->orderId;
        
        // Fetch updated record in the database, and do what you need with it
        $status = DB::table('selcom_payments')
            ->where('order_id', $orderId)
            ->value('payment_status');
        
        if ($status === 'PENDING') {
            $status = Selcom::orderStatus($orderId); 
 
            /* {
                "reference" : "0289999288",
                "resultcode" : "000",
                "result" : "SUCCESS",
                "message" : "Order fetch successful",
                "data": [{"order_id":"123", "creation_date":"2019-06-06 22:00:00", "amount":"1000", "payment_status":"PENDING","transid":null,"channel":null,"reference":null,"phone":null}]
           } */

            // That's a sample status value. Because it's still pending, you can either wait for Selcom to send data here again or create a Laravel job that queries the status after a certain interval
        }
    }
}

Check order status

To query order statuses to Selcom, simply run a query like the one above;

use Bryceandy\Selcom\Facades\Selcom;
use Illuminate\Support\Facades\DB;

$order = Selcom::orderStatus($orderId);

Once you have obtained the order data, you can use it as you wish.

The example below updates the payment in the database (which isn't necessary because the package already does that for you);

DB::table('selcom_payments')->where('order_id', $orderId)
    ->update(array_merge(
        'payment_status' => $order['payment_status'],
        ($order['payment_status'] === 'COMPLETED'
            ? [
                'selcom_transaction_id' => $order['transid'],
                'channel' => $order['channel'],
                'reference' => $order['reference'],
                'msisdn' => $order['msisdn'],
            ]
            : []
        )
    ));

List orders

To list all orders made to Selcom, simply indicate from_date and to_date;

use Bryceandy\Selcom\Facades\Selcom;

$fromDate = '2021-02-16';
$toDate = '2021-12-25';

Selcom::listOrders($fromDate, $toDate);

Cancel order

To cancel a Selcom order, simply run;

use Bryceandy\Selcom\Facades\Selcom;

Selcom::cancelOrder($orderId);

 

That's all about checkout. We can explore other APIs in future articles. In the meantime, enjoy the simplicity in making payments with Laravel 🤟

Updated 03:11 Nov 24 '23

If you like this content, please consider buying me coffee.
Thank you for your support!

Become a Patron!