Lesson 6: A Step by Step Tutorial on How to Fix Bug on Registering Confirmation and Validation URL’s to M-Pesa C2B Integration on Daraja Using Django 2.2 and Python 3.7

Lesson 6: A Step by Step Tutorial on How to Fix Bug on Registering Confirmation and Validation URL’s to M-Pesa C2B Integration on Daraja Using Django 2.2 and Python 3.7

Hello and welcome to this Python/Django tutorial series, my name is Henry Mbugua and I will be taking you through the various aspect and new answers of M-pesa Integration using Django web framework and Python 3.7. In lesson 5, we learned how to register confirmation and validation URL’s, however, we had some challenges with getting a successful response from Safaricom M-pesa API, in this lesson we are going to learn how we can fix our bug.

The Error we encountered in Lesson 5

In lesson 5, we successfully called Safaricom sandbox C2B register endpoint we got the following error.

Error

Where the response code was 409, in the HTTP status code, the 409 code is used in situations where the user might able to resolve the conflict. You can learn more about the HTTP code status here.

Fixing Registering Confirmation and Validation

The first step to do is to log in to the M-pesa Daraja portal and visit this URL: https://developer.safaricom.co.ke/test_credentials this is where you get the test credentials for C2B sandbox. Here is a screenshot of the page:

Test Credentials
test credentials

If you take a close look at the test credentials provided by Safaricom you will see we have the following:

  1. Shortcode 1 – 600344
  2. Shortcode 2 – 600000
  3. Lipa na Mpesa Online Shortcode – 174379

Our Bug

In lesson 3, we learned how to create an STK push and we used Lipa na Mpesa Online Shortcode (174379). When you open mpesa_api/mpesa_credentials.py file you get the following code:

import requests
import json
from requests.auth import HTTPBasicAuth
from datetime import datetime
import base64


class MpesaC2bCredential:
    consumer_key = 'cHnkwYIgBbrxlgBoneczmIJFXVm0oHky'
    consumer_secret = '2nHEyWSD4VjpNh2g'
    api_URL = 'https://sandbox.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials'


class MpesaAccessToken:
    r = requests.get(MpesaC2bCredential.api_URL,
                     auth=HTTPBasicAuth(MpesaC2bCredential.consumer_key, MpesaC2bCredential.consumer_secret))
    mpesa_access_token = json.loads(r.text)
    validated_mpesa_access_token = mpesa_access_token['access_token']


class LipanaMpesaPpassword:
    lipa_time = datetime.now().strftime('%Y%m%d%H%M%S')
    Business_short_code = "174379"
    passkey = 'bfb279f9aa9bdbcf158e97dd71a467cd2e0c893059b10f78e6b72ada1ed2c919'

    data_to_encode = Business_short_code + passkey + lipa_time

    online_password = base64.b64encode(data_to_encode.encode())
    decode_password = online_password.decode('utf-8')

On line 23, we defined our Shortcode which is Lipa na Mpesa Online Shortcode. From Safaricom, “the Lipa na Mpesa Online Shortcode is meant for STK push only.” And that is why we were not able to register our confirmation and validation URL.

To fix our bug, update mpesa_api/mpesa_credentials.py file and make sure it has the following code:

import requests
import json
from requests.auth import HTTPBasicAuth
from datetime import datetime
import base64


class MpesaC2bCredential:
    consumer_key = 'cHnkwYIgBbrxlgBoneczmIJFXVm0oHky'
    consumer_secret = '2nHEyWSD4VjpNh2g'
    api_URL = 'https://sandbox.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials'


class MpesaAccessToken:
    r = requests.get(MpesaC2bCredential.api_URL,
                     auth=HTTPBasicAuth(MpesaC2bCredential.consumer_key, MpesaC2bCredential.consumer_secret))
    mpesa_access_token = json.loads(r.text)
    validated_mpesa_access_token = mpesa_access_token['access_token']


class LipanaMpesaPpassword:
    lipa_time = datetime.now().strftime('%Y%m%d%H%M%S')
    Business_short_code = "174379"
    Test_c2b_shortcode = "600344"
    passkey = 'bfb279f9aa9bdbcf158e97dd71a467cd2e0c893059b10f78e6b72ada1ed2c919'

    data_to_encode = Business_short_code + passkey + lipa_time

    online_password = base64.b64encode(data_to_encode.encode())
    decode_password = online_password.decode('utf-8')

On line 24, we have defined a new variable called Test_c2b_shortcode and assigned it Shortcode 1 (600344). Now open mpesa_api/views.py file and make sure it has the following code:

from django.http import HttpResponse, JsonResponse
import requests
from requests.auth import HTTPBasicAuth
import json
from . mpesa_credentials import MpesaAccessToken, LipanaMpesaPpassword
from django.views.decorators.csrf import csrf_exempt
from .models import MpesaPayment


def getAccessToken(request):
    consumer_key = 'cHnkwYIgBbrxlgBoneczmIJFXVm0oHky'
    consumer_secret = '2nHEyWSD4VjpNh2g'
    api_URL = 'https://sandbox.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials'

    r = requests.get(api_URL, auth=HTTPBasicAuth(consumer_key, consumer_secret))
    mpesa_access_token = json.loads(r.text)
    validated_mpesa_access_token = mpesa_access_token['access_token']

    return HttpResponse(validated_mpesa_access_token)


def lipa_na_mpesa_online(request):
    access_token = MpesaAccessToken.validated_mpesa_access_token
    api_url = "https://sandbox.safaricom.co.ke/mpesa/stkpush/v1/processrequest"
    headers = {"Authorization": "Bearer %s" % access_token}
    request = {
        "BusinessShortCode": LipanaMpesaPpassword.Business_short_code,
        "Password": LipanaMpesaPpassword.decode_password,
        "Timestamp": LipanaMpesaPpassword.lipa_time,
        "TransactionType": "CustomerPayBillOnline",
        "Amount": 1,
        "PartyA": 254728851119,  # replace with your phone number to get stk push
        "PartyB": LipanaMpesaPpassword.Business_short_code,
        "PhoneNumber": 254728851119,  # replace with your phone number to get stk push
        "CallBackURL": "https://sandbox.safaricom.co.ke/mpesa/",
        "AccountReference": "Henry",
        "TransactionDesc": "Testing stk push"
    }

    response = requests.post(api_url, json=request, headers=headers)
    return HttpResponse('success')


@csrf_exempt
def register_urls(request):
    access_token = MpesaAccessToken.validated_mpesa_access_token
    api_url = "https://sandbox.safaricom.co.ke/mpesa/c2b/v1/registerurl"
    headers = {"Authorization": "Bearer %s" % access_token}
    options = {"ShortCode": LipanaMpesaPpassword.Test_c2b_shortcode,
               "ResponseType": "Completed",
               "ConfirmationURL": "https://79372821.ngrok.io/api/v1/c2b/confirmation",
               "ValidationURL": "https://79372821.ngrok.io/api/v1/c2b/validation"}
    response = requests.post(api_url, json=options, headers=headers)

    return HttpResponse(response.text)


@csrf_exempt
def call_back(request):
    pass


@csrf_exempt
def validation(request):

    context = {
        "ResultCode": 0,
        "ResultDesc": "Accepted"
    }
    return JsonResponse(dict(context))


@csrf_exempt
def confirmation(request):
    mpesa_body =request.body.decode('utf-8')
    mpesa_payment = json.loads(mpesa_body)

    payment = MpesaPayment(
        first_name=mpesa_payment['FirstName'],
        last_name=mpesa_payment['LastName'],
        middle_name=mpesa_payment['MiddleName'],
        description=mpesa_payment['TransID'],
        phone_number=mpesa_payment['MSISDN'],
        amount=mpesa_payment['TransAmount'],
        reference=mpesa_payment['BillRefNumber'],
        organization_balance=mpesa_payment['OrgAccountBalance'],
        type=mpesa_payment['TransactionType'],

    )
    payment.save()

    context = {
        "ResultCode": 0,
        "ResultDesc": "Accepted"
    }

    return JsonResponse(dict(context))

The only thing we have changed is on line 49, we are passing the new Shortcode 600344 to our options when registering our urls.

Running Our Local Development Server Using Ngrok

Running our application our Django application using Ngrok is super easy, we are assuming that you have already downloaded Ngrok to your machine. On my terminal, I am going to run my Django application using the following command:

python manage.py runserver

Here is the output of my terminal:

Development server
Development server

From my terminal, I am able to tell that my Django application is running on port 8000. The next is run my Ngrok, All I have to do is to locate my Ngrok download and run the following command:

./ngrok http 8000

Here is the output of my terminal:

Ngrok server
Ngrok server

From my terminal, I am able to locate the secure tunnel which is forwarding to my localhost at port 8000. Our secure URL is the one that has https, in this case, https://79372821.ngrok.io/

NB: Remember to update your settings.py file and views.py file as we did in lesson 5

How to Register Confirmation and Validation URL

To register the confirmation and validation URL, we are going to use a postman. Open postman and in the URL use https://91563395.ngrok.io/api/c2b/register

And hit send.

NB: Make sure to replace the URL with your Ngrok URL.

Here is a screenshot of my postman results:

Success Registration

Now we get a success message from Safaricom Mpesa API. Cheers to a job well done!

Task

Now you are all set with C2B M-pesa Integration, in this tutorial series we have learned a lot of great stuff regard Mpesa API integration using the Django web framework. I believe now we ready to take up the next challenge of exploring Mpesa API on our own.

The following are some of the Mpesa API you can explore:

  1. B2C
  2. Transactions status
  3. Account balance.
Mpesa API's
Mpesa API’s

Important Links

  1. Mpesa Go Live process
  2. Mpesa API Explorer
  3. Safaricom Mpesa API Contacts

With that, we conclude the Mpesa Tutorial series. It has been a joy learning and sharing knowledge on Mpesa API integration using the Django web framework and python 3.7.

Goal Achieved in This Lesson

In this lesson, we have achieved the following:

  1. We have learned how to debug our URL registering error.
  2. We have successfully registered our confirmation and validation urls.

To get the code associated with this lesson visit Python/Django Mpesa Integration.

Facebook Comments

Close Menu