Lesson 3: A Step by Step Tutorial on How to develop C2B Integration to M-Pesa on Daraja Using Laravel 6.9 and PHP 7.3

Lesson 3: A Step by Step Tutorial on How to develop C2B Integration to M-Pesa on Daraja Using Laravel 6.9 and PHP 7.3

Hello and welcome to this PHP/Laravel tutorial series, my name is Henry Mbugua, I will be taking through the various aspects and new answers of M-Pesa integration using Laravel web framework and PHP 7.3. Laravel is one of the most popular PHP frameworks and help you build an application from ground up with expressive, elegant syntax. In Lesson 2, we learned about STK push integration to M-Pesa API, in this lesson we are going to continue with our tutorial series and we are going to learn how to create M-Pesa migrations and create confirmation and validation method.

Creating M-Pesa Migration

Laravel comes with a very powerful migration system that behaves like version control for your databases, which allows the development team to easily modify and share the applications database schema. Visit Laravel migrations to learn more about the migrations, in this tutorial we are going to create one table for storing our transactions. In this tutorial series, we are going to create an Eloquent model together with a database migration by running the following command:

php artisan make:model MpesaTransaction –m
Model and Migration creation
Model and Migration creation

From the terminal, we can tell that our command runs successfully without any errors. The next step is to define our columns in the newly created migration file. Before we can define our column in the created migration, we need to what Safaricom Mpesa api sends as a confirmation response. Here is a screenshot of Safaricom confirmation response for C2B api:

Safaricom Mpesa confirmation response.
Safaricom Mpesa confirmation response.

Now that we know what Safaricom sends as confirmation response, open the mpesa_transaction_table.php file located in database/migrations folder and make sure it has the following code:

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateMpesaTransactionsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('mpesa_transactions', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('FirstName')->nullable();
            $table->string('MiddleName')->nullable();
            $table->string('LastName')->nullable();
            $table->string('TransactionType')->nullable();
            $table->string('TransID')->nullable();
            $table->string('TransTime')->nullable();
            $table->string('BusinessShortCode')->nullable();
            $table->string('BillRefNumber')->nullable();
            $table->string('InvoiceNumber')->nullable();
            $table->string('ThirdPartyTransID')->nullable();
            $table->string('MSISDN')->nullable();
            $table->decimal('TransAmount', 8, 2)->nullable();
            $table->decimal('OrgAccountBalance', 8, 2)->nullable();
            $table->softDeletes();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('mpesa_transactions');
    }
}

The next step is to run all our outstanding migrations, running the following command:

php artisan migrate

NB: Make sure your database connection in .env file.

Here is the output of my terminal,

Migration sync to database
Migration sync to database

The next step is to create the validation and confirmation method, we are going to start with the validation method and then confirmation method, open our MpesaController.php file and make sure it has the following code:

<?php

namespace App\Http\Controllers;

use App\MpesaTransaction;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Storage;

class MpesaController extends Controller
{

    /**
     * Lipa na M-PESA password
     * */

    public function lipaNaMpesaPassword()
    {
        $lipa_time = Carbon::rawParse('now')->format('YmdHms');
        $passkey = "bfb279f9aa9bdbcf158e97dd71a467cd2e0c893059b10f78e6b72ada1ed2c919";
        $BusinessShortCode = 174379;
        $timestamp =$lipa_time;

        $lipa_na_mpesa_password = base64_encode($BusinessShortCode.$passkey.$timestamp);
        return $lipa_na_mpesa_password;
    }


    /**
     * Lipa na M-PESA STK Push method
     * */

    public function customerMpesaSTKPush()
    {
        $url = 'https://sandbox.safaricom.co.ke/mpesa/stkpush/v1/processrequest';

        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type:application/json','Authorization:Bearer '.$this->generateAccessToken()));


        $curl_post_data = [
            //Fill in the request parameters with valid values
            'BusinessShortCode' => 174379,
            'Password' => $this->lipaNaMpesaPassword(),
            'Timestamp' => Carbon::rawParse('now')->format('YmdHms'),
            'TransactionType' => 'CustomerPayBillOnline',
            'Amount' => 5,
            'PartyA' => 254728851199, // replace this with your phone number
            'PartyB' => 174379,
            'PhoneNumber' => 254728851199, // replace this with your phone number
            'CallBackURL' => 'https://blog.hlab.tech/',
            'AccountReference' => "H-lab tutorial",
            'TransactionDesc' => "Testing stk push on sandbox"
        ];

        $data_string = json_encode($curl_post_data);

        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_POST, true);
        curl_setopt($curl, CURLOPT_POSTFIELDS, $data_string);

        $curl_response = curl_exec($curl);

        return $curl_response;
    }


    public function generateAccessToken()
    {
        $consumer_key="sMpgnYW62glBlxPXbyTBEGdPib8eJLOL";
        $consumer_secret="IcK2PkAFArVVVffU";
        $credentials = base64_encode($consumer_key.":".$consumer_secret);

        $url = "https://sandbox.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials";
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_HTTPHEADER, array("Authorization: Basic ".$credentials));
        curl_setopt($curl, CURLOPT_HEADER,false);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);

        $curl_response = curl_exec($curl);
        $access_token=json_decode($curl_response);
        return $access_token->access_token;
    }


    /**
     * J-son Response to M-pesa API feedback - Success or Failure
     */
    public function createValidationResponse($result_code, $result_description){
        $result=json_encode(["ResultCode"=>$result_code, "ResultDesc"=>$result_description]);
        $response = new Response();
        $response->headers->set("Content-Type","application/json; charset=utf-8");
        $response->setContent($result);
        return $response;
    }


    /**
     *  M-pesa Validation Method
     * Safaricom will only call your validation if you have requested by writing an official letter to them
     */

    public function mpesaValidation(Request $request)
    {
        $result_code = "0";
        $result_description = "Accepted validation request.";
        return $this->createValidationResponse($result_code, $result_description);
    }

    /**
     * M-pesa Transaction confirmation method, we save the transaction in our databases
     */

    public function mpesaConfirmation(Request $request)
    {
        $content=json_decode($request->getContent());

        $mpesa_transaction = new MpesaTransaction();
        $mpesa_transaction->TransactionType = $content->TransactionType;
        $mpesa_transaction->TransID = $content->TransID;
        $mpesa_transaction->TransTime = $content->TransTime;
        $mpesa_transaction->TransAmount = $content->TransAmount;
        $mpesa_transaction->BusinessShortCode = $content->BusinessShortCode;
        $mpesa_transaction->BillRefNumber = $content->BillRefNumber;
        $mpesa_transaction->InvoiceNumber = $content->InvoiceNumber;
        $mpesa_transaction->OrgAccountBalance = $content->OrgAccountBalance;
        $mpesa_transaction->ThirdPartyTransID = $content->ThirdPartyTransID;
        $mpesa_transaction->MSISDN = $content->MSISDN;
        $mpesa_transaction->FirstName = $content->FirstName;
        $mpesa_transaction->MiddleName = $content->MiddleName;
        $mpesa_transaction->LastName = $content->LastName;
        $mpesa_transaction->save();


        // Responding to the confirmation request
        $response = new Response();
        $response->headers->set("Content-Type","text/xml; charset=utf-8");
        $response->setContent(json_encode(["C2BPaymentConfirmationResult"=>"Success"]));


        return $response;
    }

}

Let’s understand the code that we have added in MpesaController.php file:

  • Line 93 to 99 – we have created a method called createValidationResponse () which takes two parameters namely result_code and result_description. Safaricom expects you to send a json response to either to accept payment or decline the payment.
  • Line 94 – we create a variable called result_code and we use json_encode to convert our object into a json representation.
  • Line 95 –  we create a new instance of the response.
  • Line 96 – we set our header by defining our content to json.
  • Line 97 –  we set our content.
  • Line 98 –  we return our response.
  • Line 107 to 112 – we define our Mpesa validation method. At the moment, this method does nothing useful apart from accepting payment.
  • Line 109 – we define our response code to zero, which tells Safaricom to allow the transaction. If you use any other number the transaction will be rejected.
  • Line 110 – we define our description, in this case, we accept the payment.
  • Line 111 – we call our createValidationResponse () method and pass our validation parameters.
  • Line 118 to 146 – we define our Mpesa confirmation method; this method saves our transactions in our databases.
  • Line 120 – we create a variable called content and we use the json_decode () method which converts json string into a php variable. We also use a request to pass the Safaricom response.
  • Line 122 – we create a variable called mpesa_transaction and create a new instance of our MpesaTransaction model.
  • Line 124 to 135 – we map our database column with the Safaricom response.
  • Line 136 –  we save our transaction in the database.

Now that we understand the code we have just added in the MpesaController.php file. The next step is to create our confirmation and validation urls. Open api.php file, located in routes folder and make sure it has the following code:

<?php

use Illuminate\Http\Request;

/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/

Route::middleware('auth:api')->get('/user', function (Request $request) {
    return $request->user();
});

Route::post('v1/access/token', 'MpesaController@generateAccessToken');
Route::post('v1/hlab/stk/push', 'MpesaController@customerMpesaSTKPush');
Route::post('v1/hlab/validation', 'MpesaController@mpesaValidation');
Route::post('v1/hlab/transaction/confirmation', 'MpesaController@mpesaConfirmation');

In the api.php file, we have added two new routes. Line 22, we have created our validation URL and we have mapped it to our validation method in MpesaController.php file. Line 23, we have created our confirmation URL and we have mapped it to our confirmation method in MpesaController.php file

Goal Achieved in this Lesson

In this lesson, we have achieved the following:

  • We have learned how to create our Mpesa migration.
  • We have learned how to create a validation and confirmation method.
  • We have learned how to create our validation and confirmation URL’s

With that we conclude this lesson, to get the code associated with this lesson visit Laravel Mpesa API Integration.

The next tutorial – Lesson 4

Facebook Comments