Pesapal.com

IPN

So, once you have posted a transaction to PesaPal, how do you find if the payment has competed? Or failed?

PesaPal can send you a notification every time a status change has happened on one of your transactions following which you can query for the status. This is referred to as IPN or Instant Payment Notifications.

Let's take a look at how this works in detail.

Steps

Step 1: Enable IPN

To enable IPN, you need to set the URL at which you will be listening to the PesaPal notifications. To do this, log in to your PesaPal Merchant account, click on the "IPN Settings" menu, and enter the URL.

Note: use https://demo.pesapal.com for testing

Step 2: Listen to the IPN

PesaPal will call the URL you entered above with the following query parameters:

  1. pesapal_notification_type=CHANGE
  2. pesapal_transaction_tracking_id=<the unique tracking id of the transaction>
  3. pesapal_merchant_reference=<the merchant reference>

You must respond to the HTTP request with the same data that you received from PesaPal. For example:

pesapal_notification_type=CHANGE&pesapal_transaction_tracking_id=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXX&pesapal_merchant_reference=12345

PesaPal will retry a number of times, if we don't receive the correct response (for example due to network failure).

Step 3: Query for the Status

At this point you may be wondering why PesaPal didn't send you the status of the transaction? We only send you the
pesapal_transaction_tracking_id and the pesapal_merchant_reference for security reasons.

Once you have these two values, you can query PesaPal over a secure SSL connection (that's the https in https://www.pesapal.com) for the status of the transaction using the QueryPaymentStatus API method.

To call the QueryPaymentStatus API method, you need to package the request using OAuth, similar to when you posted a transaction to PesaPal.

Sample Code

PHP

<?php
include_once('oauth.php');
$consumer_key="xxxxxxxxxxxxxxxxxx";//Register a merchant account on
                   //demo.pesapal.com and use the merchant key for testing.
                   //When you are ready to go live make sure you change the key to the live account
                   //registered on www.pesapal.com!
$consumer_secret="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";// Use the secret from your test
                   //account on demo.pesapal.com. When you are ready to go live make sure you 
                   //change the secret to the live account registered on www.pesapal.com!
$statusrequestAPI = 'https://demo.pesapal.com/api/querypaymentstatus';//change to      
                   //https://www.pesapal.com/api/querypaymentstatus' when you are ready to go live!

// Parameters sent to you by PesaPal IPN
$pesapalNotification=$_GET['pesapal_notification_type'];
$pesapalTrackingId=$_GET['pesapal_transaction_tracking_id'];
$pesapal_merchant_reference=$_GET['pesapal_merchant_reference'];

if($pesapalNotification=="CHANGE" && $pesapalTrackingId!='')
{
   $token = $params = NULL;
   $consumer = new OAuthConsumer($consumer_key, $consumer_secret);
   $signature_method = new OAuthSignatureMethod_HMAC_SHA1();

   //get transaction status
   $request_status = OAuthRequest::from_consumer_and_token($consumer, $token, "GET", $statusrequestAPI, $params);
   $request_status->set_parameter("pesapal_merchant_reference", $pesapal_merchant_reference);
   $request_status->set_parameter("pesapal_transaction_tracking_id",$pesapalTrackingId);
   $request_status->sign_request($signature_method, $consumer, $token);

   $ch = curl_init();
   curl_setopt($ch, CURLOPT_URL, $request_status);
   curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
   curl_setopt($ch, CURLOPT_HEADER, 1);
   curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
   if(defined('CURL_PROXY_REQUIRED')) if (CURL_PROXY_REQUIRED == 'True')
   {
      $proxy_tunnel_flag = (defined('CURL_PROXY_TUNNEL_FLAG') && strtoupper(CURL_PROXY_TUNNEL_FLAG) == 'FALSE') ? false : true;
      curl_setopt ($ch, CURLOPT_HTTPPROXYTUNNEL, $proxy_tunnel_flag);
      curl_setopt ($ch, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
      curl_setopt ($ch, CURLOPT_PROXY, CURL_PROXY_SERVER_DETAILS);
   }

   $response = curl_exec($ch);
   $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
   $raw_header  = substr($response, 0, $header_size - 4);
   $headerArray = explode("\r\n\r\n", $raw_header);
   $header      = $headerArray[count($headerArray) - 1];

   //transaction status
   $elements = preg_split("/=/",substr($response, $header_size));
   $status = $elements[1];

   curl_close ($ch);

   //UPDATE YOUR DB TABLE WITH NEW STATUS FOR TRANSACTION WITH pesapal_transaction_tracking_id $pesapalTrackingId

   if(DB_UPDATE_IS_SUCCESSFUL && $status != "PENDING")
   {
      $resp="pesapal_notification_type=$pesapalNotification&pesapal_transaction_tracking_id=$pesapalTrackingId&pesapal_merchant_reference=$pesapal_merchant_reference";
      ob_start();
      echo $resp;
      ob_flush();
      exit;
   }
}
?>
 

.Net

try
{
   var ipnType = Request["pesapal_notification_type"];
   var transactionTrackingId = Request["pesapal_transaction_tracking_id"];
   var merchantRef = Request["pesapal_merchant_reference"];

   if (UpdateIpnTransactionStatus(ipnType , transactionTrackingId , merchantRef ))
   {
      Response.ClearContent();
      Response.Write(string.Format(
              "pesapal_notification_type={0}&pesapal_transaction_tracking_id={1}&pesapal_merchant_reference={2}",
              ipnType, 
              transactionTrackingId, 
              merchantRef));
   }
}
catch (Exception ex) 
{ 
   // Handle error
}

public static bool UpdateIpnTransactionStatus(string ipnType, string transactionTrackingId, string merchantRef)
{ 
    string consumerKey = "xxxxxxxxxxxxxxxxxx";//Register a merchant account on
                   //demo.pesapal.com and use the merchant key for testing.
                   //When you are ready to go live make sure you change the key to the live account
                   //registered on www.pesapal.com!
    string consumerSecret =" xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";// Use the secret from your test
                   //account on demo.pesapal.com. When you are ready to go live make sure you 
                   //change the secret to the live account registered on www.pesapal.com!

    Uri pesapalQueryPaymentStatusUri = "https://demo.pesapal.com/api/querypaymentstatus";//change to      
                   //https://www.pesapal.com/api/querypaymentstatus' when you are ready to go live!

    IBuilder builder = new APIPostParametersBuilder()
            .ConsumerKey(consumerKey)
            .ConsumerSecret(consumerSecret)
            .OAuthVersion(EOAuthVersion.VERSION1)
            .SignatureMethod(ESignatureMethod.HMACSHA1)
            .SimplePostHttpMethod(EHttpMethod.GET)
            .SimplePostBaseUri(pesapalQueryPaymentStatusUri );

    // Initialize API helper
    var helper = new APIHelper(builder);

    if (ipnType == "CHANGE")
    {
        // query pesapal for status >> format of the result is pesapal_response_data=<status>
        string result = helper.PostGetQueryPaymentStatus(pesapal_tracking_id, reference); 
        string[] resultParts = result.Split(new char[] { '=' }); 
        string paymentStatus = resultParts[1]; /* Possible values:  
                           PENDING, COMPLETED, FAILED or INVALID*/ 

        // UPDATE YOUR DATABASE: SET THE STATUS OF THIS TRANSACTION TO paymentStatus
        
        //IF DATABASE WAS NOT UPDATED OR STATUS == PENDING, RETURN FALSE TO AVOID SENDING AN ACKNOWLEDGEMENT TO PESAPAL
        if(DB_UPDATE_IS_NOT_SUCCESSFUL || paymentStatus == "PENDING"){
            return false;
        }

     }
     else
     {
         return false;
     }

     return true;
}