Pesapal.com

Point of sale (POS)

Refund Request

Definitions

The refund request endpoint allow you to refund a charge that has previously been processed but not yet refunded. Funds will be refunded to the credit / debit card or mobile money wallet that was originally charged.

The ability to process a refund has the following limitations:

  1. A refund has to be approved by the merchant.
  2. You can't refund more than what was originally collected.
  3. You can only refund payments with the status of COMPLETED.
  4. You can partially or fully refund a payment card payment.
  5. You can only fully refund a payment mobile payment.
  6. Refunds are performed in the currency of the original payment.
  7. Multiple refunds are not allowed. You can only request one refund against a payment.

The URL to our RequestRefund API is either:

Authentication

Bearer Token : Use token generated during authentication.

HTTP request headers

Accept: The response format, which is required for operations with a response body.
Content-Type: The request format, which is required for operations with a request body.

Parameter RequiredDescription
Accept Required Should be set to application/json
Content-Type Required Should be set to application/json

Request Parameters

ParameterTypeRequiredDescription
confirmation_code String Required This refers to payment confirmation code that was returned by the processor
amount Float Required Amount to be refunded.
username String Required Identity of the user who has initiated the refund.
remarks String Required A brief description on the reason for the refund.
Sample Request
    
    {
        "confirmation_code": "AA11BB22",
        "amount": "100.00",
        "username": "John Doe",
        "remarks": "Service not offered"
    }    

After successfully placing a refund request, a request will be sent to our finance team to start processing the refund.

Response Parameters

NameTypeDescription
error Integer 200 - Refund received successfully and is being processed. 500 - Refund rejected.
message String A brief summary of the response received.

Status 200 mean your request to process the refund has been received successfully. However, please note that this does not mean the refund has been effected. Pesapal has to get the go ahead from the merchant before finalising the refund.

Status 500 mean your request to process the refund was rejected for one reason or another. Refer to the error message for more details.

Sample Response
    
    {
        "status": "200",
        "message": "Refund request successfully"
    }  

The refund API uses the confirm code for identification. It's important that you store all payment confirmation codes as returned in the Get Transaction Status Endpoint

Recurring / Subscription Based Payments

Definitions

Recurring payment is a payment model where customers authorize the business to pull funds from their accounts automatically at regular intervals for the goods and services provided to them on an ongoing basis.

With Pesapal's subscription based payments, customers can set automated card payments on their account where they can be debited automatically at a different set times. Examples of services one can enroll to include cable bills, cell phone bills, gym membership fees, utility bills and magazine subscriptions. These payments can be set to run an various intervals such as daily, weekly, monthly or yearly.

How can recurring payments benefit your business?

  • Saves customers time: Customers no longer have to go through the payment process every time they need to make a payment.
  • Ensures prompt payment: Businesses no longer need to worry about getting paid on time. Since the payments are automated, they no longer need to send out overdue payment reminders.
  • Boosts customer loyalty: With a subscription model, businesses can form closer relationships with their customers.
  • Cash flow prediction: Businesses can easily predict their cash flow, which helps with business strategy.
  • Lowers billing and collection costs: Businesses no longer need to chase after missed payments, freeing up their time to concentrate on other elements of the business.

How do i enable recurring payment for my customers?

Enable our subscription based payments by passing an additional account_number field when sending data to our SubmitOrderRequest endpoint. This account_number should relate to an account number / invoice number that helps you identify the payment.

Note: It's critical that you get to understand all other Pesapal API 3.0 endpoints before implementing the recurring feature. Click here to get started.

In adition to the SubmitOrderRequest parameters, include one more param as show below.

Parameter RequiredDescription
account_number Optional Customer's identification number know to your system. This can be an invoice number or an account number.

Sample Request
    {
        "id": "AA1122-3344ZZ",
        "currency": "KES",
        "amount": 100.00,
        "description": "Payment description goes here",
        "callback_url": "https://www.myapplication.com/response-page",
        "notification_id": "fe078e53-78da-4a83-aa89-e7ded5c456e6",
        "billing_address": {
            "email_address": "[email protected]",
            "phone_number": "0723xxxxxx",
            "country_code": "KE",
            "first_name": "John",
            "middle_name": "",
            "last_name": "Doe",
            "line_1": "Pesapal Limited",
            "line_2": "",
            "city": "",
            "state": "",
            "postal_code": "",
            "zip_code": ""
        },
        "account_number": "555-678"
    }    

After successfully processing your request using the SubmitOrderRequest endpoint, the customer will be shown an option to opt into the recurring model on the Pesapal iframe during payment. The customer will then configure the frequency (Daily, weekly, monthly, quarterly or yearly), set a start and enddate, and finally enter an amount to be automatically deducted from their card on each payment cycle.

Pesapal Recurring Form

Once the customer has made a successful payment, Pesapal will automatically create a scheduled subscription on their behalf and an email alert will be sent to the provided card billing email that was used during the payment proccess, notifying them of the newly created subscription together with a link they can access a dashboard to manage their subscription.

Pesapal will NOT store the customer's card details. Instead, Pesapal has implemented the card tokenization technology.

Credit card tokenization is the process of de-identifying sensitive cardholder data by converting it to a string of randomly generated numbers called a "token." Similar to encryption, tokenization obfuscates the original data to render it unreadable to a user. Unlike encryption, however, credit card tokenization is irreversible.

Is it possible to send the extra subscription parameters (Frequency, amount, period) via the API?

Yes, in cases where your application already handles the process where the customer opts into a subscription based model from your application, Pesapal allows your to send these extra parameters via the API. This ensures that the user does not have to fill in the same details again (on your application and on the Pesapal Iframe).

However, it's important to note that the customer MUST accept to enroll to your subscription on the iframe. They will however not be able to edit the subscription details on the iframe.

In adition to the account_number parameter included in the SubmitOrderRequest, you are required to send the following parameter.

Parameter RequiredDescription
subscription_details Optional Customer Subscription Object You can pass subscription data to Pesapal allowing a user to setup recurring payment..
Subscription Object

NameTypeRequiredDescription
start_date String Mandatory Your subscription's start date in the format dd-MM-yyyy e.g 24-01-2023 representing 24th Jan 2023
end_date String Mandatory Your subscription's end date in the format dd-MM-yyyy e.g 31-12-2023 represeting 31st Dec 2023
frequency String Mandatory The period billed to the account is set out in the user contract. For instance, if users subscribe to a monthly service. Accepted values include DAILY, WEEKLY, MONTHLY or YEARLY

Sample Request
    {
        "id": "AA1122-3344ZZ",
        "currency": "KES",
        "amount": 100.00,
        "description": "Payment description goes here",
        "callback_url": "https://www.myapplication.com/response-page",
        "notification_id": "fe078e53-78da-4a83-aa89-e7ded5c456e6",
        "billing_address": {
            "email_address": "[email protected]",
            "phone_number": "0723xxxxxx",
            "country_code": "KE",
            "first_name": "John",
            "middle_name": "",
            "last_name": "Doe",
            "line_1": "Pesapal Limited",
            "line_2": "",
            "city": "",
            "state": "",
            "postal_code": "",
            "zip_code": ""
        },
        "account_number": "555-678",
        "subscription_details": {
            "start_date": "24-01-2023",
            "end_date": "31-12-2023",
            "frequency": "DAILY"
        }
    }    

After successfully processing your request using the SubmitOrderRequest endpoint, the customer will be shown an option to opt into the recurring model on the Pesapal iframe during payment. The iframe will this time load without he options to re-select the Frequecy, period and dates.

Pesapal Recurring Form

Can a customer opt out of recurring payments before the end date?

Yes, customers have the right to cancel their subscription at anytime. Pesapal will send them email alerts a day or two prior to charging their cards. This ensures customers are always aware of all upcoming charges giving them the freedom to opt out or pausing their subscriptions.

Which cards are currently supported?

We currently support Visa and MasterCard for recurring payments. More card options will be enabled in the near future.

How will Pesapal alert my business about successful recurring payments?

Once a schedule is created and executed successfully, Pesapal will trigger an IPN (Instant Payment Notification) to the IPN endpoint you provided when calling the SubmitOrderRequest endpoint. This IPN call will have the OrderNotificationTypei> set as RECURRING.

Sample IPN URL: https://www.myapplication.com/response-page?OrderTrackingId=b945e4af-80a5-4ec1-8706-e03f8332fb04&OrderMerchantReference=555-678&OrderNotificationType=RECURRING

Recurring IPN Details

The IPN alert will either be a GET or POST request, depending on which HTTP method you selected when registering the IPN URL. Click here for more details on how to register your IPN endpoint.

The IPN call will have the following parameters;

ParameterTypeDescription
OrderTrackingId String Unique order id generated by Pesapal.
OrderNotificationType String Value set as RECURRING to represent a Recurring IPN call.
OrderMerchantReference String Your account number received as part of the SUBMIT ORDER REQUEST.

The IPN call will NOT have all details of the payment for security reasons. As such, you will be required to fetch the payment using the GetTransactionStatus API once the IPN URL is triggered.

In addition to the normal payment status details received from the GetTransactionStatus endpoint, Pesapal will append an object subscription_transaction_info containing some additional recurring payment data

Recurring Payments Extra Data (subscription_transaction_info)

NameDescription
account_reference Customer's identification number know to your system. This can be an invoice number or an account number.
amount Amount paid by the customer.
first_name Customer's first name.
last_name Customer's last name.
correlation_id Pesapal's unique recurring payment identifier / id.

Sample Response
    {
        "payment_method": "Visa",
        "amount": 100,
        "created_date": "2022-04-30T07:41:09.763",
        "confirmation_code": "6513008693186320103009",
        "payment_status_description": "Failed",
        "description": "Unable to Authorize Transaction.Kindly contact your bank for assistance",
        "message": "Request processed successfully",
        "payment_account": "476173**0010",
        "call_back_url": "https://test.com/?OrderTrackingId=7e6b62d9-883e-440f-a63e-e1105bbfadc3&OrderMerchantReference=555-678",
        "status_code": 2,
        "merchant_reference": "1515111111",
        "payment_status_code": "",
        "currency": "KES",
        "subscription_transaction_info": {
            "account_reference": "555-678",
            "amount": 100,
            "first_name": "John",
            "last_name": "Doe",
            "correlation_id": 111222
        },
        "error": {
            "error_type": null,
            "code": null,
            "message": null,
            "call_back_url": null
        },
        "status": "200"
    }    

What Next?

Once you've fetched the recurring data, you are then required to store the same in your system and provide services / goods as subscribed.

Your IPN endpoint should then respond to Pesapal with a json string confirming service delivery. Part of the json string contains a status parameter that should be set as 200 (meaning request was received and processed) or 500 (meaning request was received but there was an issue providing the services).

Sample JSON Response String: {"orderNotificationType":"RECURRING","orderTrackingId":"d0fa69d6-f3cd-433b-858e-df86555b86c8","orderMerchantReference":"555-678","status":200}

NB: Constant complains from your customers about service / goods not delivered which were paid using recurring / subscription based payment mode will lead to the subscriptions being terminated and your profile banned from using the feature.

PAGE NOT FOUND

Sorry the page you are looking for cannot be found,kindly use the menus at the top of the page to find what you are looking for

 

  1. Don't spam/troll the forum. Repeatedly doing this will result in a ban.
  2. Only one account per person is permitted.
  3. If you make a post, put it in the correct category.
  4. Be nice, and professional. If you disagree with a post someone posted, feel free to post that you disagree, and why you disagree. If you do, please keep it nice and professional.
  5. No use of abusive words that would cause us to lose other members.
  6. No lying or presenting blatantly false information with an intent to deceive
  7. No Advertising - You are not permitted to make money using this forum.
  8. Keep all posts on-topic.
  9. Check that your question has not been answered anywhere else on the site. Use the search feature.

Test your integration on https://demo.pesapal.com before you take your site live!

1. Add reference to PesaPal.API.dll

Download the version of PesaPal.API.dll most suitable for you from the downloads section.

2. Create a page to display the PesaPal payment processing form

Example: Payment.aspx

You can now embed PesaPal directly in your site, providing a seamless experience to your customers.

You can do this by inserting an iframe on the page on your site customers land on when they checkout:

<iframe src="/<%=GetPesapalUrl()%>" width="100%" height="620px" frameborder="0" scrolling="auto" />

Please note: the value for the src attribute should be "<%=GetPesapalUrl()%>" (without the leading /). [It is being added automatically by our CMS and we are still trying to figure out how to get rid of it!]

In the code behind file, Payment.aspx.cs, add the method GetPesapalUrl(). This is where most of the work happens.

using Pesapal.API; 
using System.Linq; 
... 
protected string GetPesapalUrl() 
{ 
   Uri pesapalPostUri = new Uri("https://demo.pesapal.com/API/PostPesapalDirectOrderV4"); /*change to       
      https://www.pesapal.com/API/PostPesapalDirectOrderV4 when you are ready to go live!*/
   Uri pesapalCallBackUri = new Uri(/* link to the page on your site users will be 
      redirected to when the payment process has been completed */); 
   
// Setup builder
   IBuilder builder = new APIPostParametersBuilderV2() 
           .ConsumerKey(/* Your PesaPal Consumer Key  
               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!*/) 
           .ConsumerSecret(/* Your PesaPal Consumer Secret
                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!*/) 
           .OAuthVersion(EOAuthVersion.VERSION1) 
           .SignatureMethod(ESignatureMethod.HMACSHA1) 
           .SimplePostHttpMethod(EHttpMethod.GET) 
           .SimplePostBaseUri(pesapalPostUri) 
           .OAuthCallBackUri(pesapalCallBackUri); 
   
   // Initialize API helper
   APIHelper<IBuilder> helper = new APIHelper<IBuilder>(builder); 
   // Populate line items
   var lineItems = new List<LineItem> { };

   // For each item purchased, add a lineItem. 
   // For example, if the user purchased 3 of Item A, add a line item as follows:
   var lineItem = 
       new LineItem
       { 
              Particulars = /* description of the item, example: Item A */, 
              UniqueId = /* some unique id for the item */, 
              Quantity = /* quantity (number of items) purchased, example: 3 */, 
              UnitCost = /* cost of the item (for 1 item) */
        }; 

   lineItem.SubTotal = (lineItem.Quantity * lineItem.UnitCost);
   lineItems.Add(lineItem); 
   // Do the same for additional items purchased
   ... 
   
   // Compose the order
   PesapalDirectOrderInfo webOrder = new PesapalDirectOrderInfo() 
   { 
       Amount = (lineItems.Sum(x => x.SubTotal)).ToString(), 
       Description = /* [required] description of the purchase */, 
       Type = "MERCHANT", 
       Reference = /* [required] a unique id, example: an order number */, 
       Email = /* [either email or phone number is required]  
                  email address of the user making the purchase */, 
       FirstName = /* [optional] user’s first name */, 
       LastName = /* [optional] user’s last name */, 
       PhoneNumber = /* [either email or phone number is required]  
                        user’s phone number */, 
       LineItems = lineItems 
   }; 

   // Post the order to PesaPal, which upon successful verification, 
   // will return the string containing the url to load in the iframe
   return helper.PostGetPesapalDirectOrderUrl(webOrder); 
} 

3. Create a page to display after the user has completed the payment process on PesaPal

Example: PaymentBeingProcessed.aspx

Note: this is the same page whose url was specified in the pesapalCallBackUri parameter in the
GetPesapalUrl() method above.

PesaPal will redirect to this page with the following query parameters:

pesapal_merchant_reference: this is the reference (a unique order id), that you passed to PesaPal when
posting the transaction.

pesapal_transaction_tracking_id: this is the unique tracking id for this transaction on PesaPal.

string reference = Request.QueryString["pesapal_merchant_reference"]; 
string pesapal_tracking_id = Request.QueryString["pesapal_transaction_tracking_id"]; 

Store the pesapal_tracking_id in your database against the order matching the reference as you will
need it for subsequently identifying the transaction and updating its payment status.

4. Listen to IPN and Query for the Status of a Transaction

Once a transaction has been posted to PesaPal, you can listen for Instant Payment Notifications on a URL on your site (see here for details).

Below is sample code that listens to notifications from PesaPal and consequently queries for the transaction status.

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){
            return false;
        }

     }
     else
     {
         return false;
     }

     return true;
}

Other PesaPal API Methods

QueryPaymentStatusByMerchantRef

QueryPaymentDetails

QueryPaymentStatusByMerchantRef

Same as QueryPaymentStatus above, but pesapal_tracking_id is not required.

string reference = /* this is the Reference you sent PesaPal when posting a transaction  
   (Note: this has to be unique for each transaction) */ 

// Setup builder
IBuilder builder = new APIPostParametersBuilder() 
 .ConsumerKey(WebManager.ConsumerKey) 
 .ConsumerSecret(WebManager.ConsumerSecret) 
 .OAuthVersion(EOAuthVersion.VERSION1) 
 .SignatureMethod(ESignatureMethod.HMACSHA1) 
 .SimplePostHttpMethod(EHttpMethod.GET) 
 .SimplePostBaseUri("https://demo.pesapal.com/api/querypaymentstatusbymerchantref"); /*When you are ready to go live
      change to https://www.pesapal.com/api/querypaymentstatusbymerchantref*/

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

try 
{ 
   // query pesapal for status >> format of the result is pesapal_response_data=<status>
   string result = helper.PostGetQueryPaymentStatus(reference); 
   string[] resultParts = result.Split(new char[] { '=' }); 
   string paymentStatus = resultParts[1]; /* Possible values:  
           PENDING, COMPLETED, FAILED or INVALID*/ 
} 
catch (Exception ex) 
{ 
   // Handle error
}

The following result will be returned to you:

pesapal_response_data=<PENDING|COMPLETED|FAILED|INVALID>

QueryPaymentDetails

Same as QueryPaymentStatus, but additional information is returned.

string reference = /* this is the Reference you sent PesaPal when posting a transaction  
   (Note: this has to be unique for each transaction) */ 
string pesapalTrackingId = /* this is the tracking id returned by PesaPal when you  
   posted a transaction */ 

// Setup builder
IBuilder builder = new APIPostParametersBuilder() 
 .ConsumerKey(WebManager.ConsumerKey) 
 .ConsumerSecret(WebManager.ConsumerSecret) 
 .OAuthVersion(EOAuthVersion.VERSION1) 
 .SignatureMethod(ESignatureMethod.HMACSHA1) 
 .SimplePostHttpMethod(EHttpMethod.GET) 
 .SimplePostBaseUri("https://demo.pesapal.com/api/querypaymentdetails");  /*When you are ready to go live
      change to https://www.pesapal.com/api/querypaymentdetails*/

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

try 
{ 
   /* query pesapal for status >> format of the result is 
 pesapal_response_data= pesapalTrackingId,paymentMethod,paymentStatus,reference 
   */ 
   string result = helper.PostGetQueryPaymentDetails(pesapalTrackingId, reference); 
   string[] resultParts = result.Split(new char[] { '=' }); 
   string paymentDetails = resultParts[1]; 
   string[] paymentDetailsParts = result.Split(new char[] { ',' }); 
   string paymentMethod = paymentDetailsParts[1]; /* example, MPESA, VISA, etc. 
   string paymentStatus = paymentDetailsParts[2]; /* Possible values:  
           PENDING, COMPLETED, FAILED or INVALID*/ 
} 
catch (Exception ex) 
{ 
   // Handle error
}

The following result will be returned to you:

pesapal_response_data=pesapalTrackingId,paymentMethod,paymentStatus,reference

pesapalTrackingId: this is the same as the parameter you sent when making the query

paymentMethod: the payment method used by the user to make the payment

paymentStatus: one of <PENDING|COMPLETED|FAILED|INVALID>

reference: this is the same as the parameter you sent when making the query