Skip to Content
Pesa VoucherDeveloper Documentation

Pesapal

Accept Pesapal-powered card, mobile money, and bank payments via a hosted checkout iframe, backed by your Pesa Voucher merchant wallet.


Pesapal Payments API

Live Base URL: https://payments.pesavoucher.com/api/v2/

No separate sandbox base URL is documented yet for these endpoints — contact support@pesavoucher.com for sandbox credentials before going live. Pesapal's own demo environment (https://cybqa.pesapal.com/pesapalv3) is available if you're integrating directly — see Direct Pesapal API Reference below.

Live Testing Note To perform real live transactions or trigger a live test webhook, please contact us: support@pesavoucher.com Telegram: Join our channel → t.me/Dev_PesaVoucher

Overview

PesaVoucher's Pesapal integration lets customers pay via Pesapal's hosted checkout — cards, mobile money, and bank options, depending on what's enabled on the underlying Pesapal merchant account — inside an iframe you embed on your site. PesaVoucher handles the Pesapal v3 OAuth token, IPN registration, and order submission internally; you only need to call the endpoints below.

Two Ways to Integrate

PathWho it's forEndpoints
PesaVoucher Pesapal Endpoints (recommended)Merchants using PesaVoucher's wrapper — no Pesapal account of your own requiredinitiate.php, callback.php, listen_pesapal.php
Direct Pesapal API (advanced)Merchants with their own Pesapal merchant account integrating Pesapal v3 directlyAuth/RequestToken, URLSetup/RegisterIPN, Transactions/SubmitOrderRequest, Transactions/GetTransactionStatus

This page documents the recommended path first, then the direct Pesapal API for reference.


Authentication

Note: the example initiate.php requests in the Pesapal Postman collection don't show the X-API-KEY / X-API-SECRET headers used by the other payment rails on this platform — only Content-Type: application/json, with merchant_id passed in the request body instead. Confirm with support whether header-based authentication is also required for your account before going live.


1. Initiate Payment

Endpoint: POST /initiate.php

Starts a Pesapal payment session and returns an iframe URL for the customer to complete payment.

curl -X POST https://payments.pesavoucher.com/api/v2/initiate.php \
-H "Content-Type: application/json" \
-d '{
"merchant_id": "MCH123",
"order_id": "ORD-2026-0417",
"amount": 1500.00,
"currency": "KES",
"description": "Order payment",
"phone_number": "254712345678",
"email_address": "customer@example.com",
"first_name": "Jane",
"last_name": "Doe"
}'

Request Parameters

ParameterTypeRequiredDescription
merchant_idstringYesYour PesaVoucher merchant identifier
order_idstringYesYour internal order/reference ID
amountfloatYesPayment amount
currencystringYesCurrency code — KES confirmed in examples
descriptionstringYesDescription shown on the Pesapal checkout
phone_numberstringYesCustomer phone, 254XXXXXXXXX format
email_addressstringYesCustomer email address
first_namestringYesCustomer first name
last_namestringYesCustomer last name
callback_urlstringNoOverride where the customer is redirected after payment. If omitted, PesaVoucher's default handler is used

Note: one example in the collection calls this endpoint at /pesapal/initiate.php instead of /initiate.php when a callback_url override is supplied. Confirm the exact path for your account with support before going live.

Response

{
"redirect_url": "https://pay.pesapal.com/iframe/PesapalIframe3/Index?OrderTrackingId=9c5add4c-1234-5678-9abc-def012345678",
"order_tracking_id": "9c5add4c-1234-5678-9abc-def012345678"
}

Additional fields (e.g. a success flag) may also be present — treat redirect_url and order_tracking_id as the fields you need.

Next step: Embed redirect_url in an iframe on your checkout page. The customer completes payment (card, mobile money, or bank, depending on what's enabled) inside the iframe.


2. Payment Callback (Browser Redirect)

Endpoint: GET /pesapal/callback.php

Pesapal redirects the customer's browser here after payment (or to your callback_url override, if supplied). PesaVoucher verifies the transaction status and updates its records.

GET /pesapal/callback.php?OrderTrackingId={order_tracking_id}&OrderMerchantReference={order_id}&OrderNotificationType=IPNCHANGE

Treat this as UX only, not your source of truth. The customer can close the browser before the redirect fires. Always confirm the final payment status from the IPN notification (below) — never credit a user based on the redirect alone.


3. IPN Listener (Server-to-Server Notification)

Endpoint: POST /listen_pesapal.php

PesaVoucher registers this URL with Pesapal on your behalf and receives a notification whenever a transaction's status changes — this is the authoritative signal that a payment completed.

POST /listen_pesapal.php?OrderTrackingId={order_tracking_id}&OrderMerchantReference={order_id}&OrderNotificationType=IPNCHANGE

You don't need to register your own IPN URL with Pesapal — PesaVoucher already has. Deposit status updates are delivered to your own configured webhook URL (see Webhooks) in PesaVoucher's normalized format.

Payment Status Values

payment_status_descriptionMeaning
COMPLETEDPayment successful — credit the user
PENDINGStill processing — keep waiting
FAILEDPayment failed — allow retry
INVALIDOrder/tracking ID not recognized
REVERSEDPayment was reversed after completing

Direct Pesapal API Reference (Advanced)

If you have your own Pesapal merchant account and want to integrate with Pesapal v3 directly instead of using the PesaVoucher wrapper above, these are the underlying calls PesaVoucher itself makes.

Pesapal Production URL: https://pay.pesapal.com/v3 Pesapal Demo/Sandbox URL: https://cybqa.pesapal.com/pesapalv3

Get Access Token

Endpoint: POST /api/Auth/RequestToken

curl -X POST https://pay.pesapal.com/v3/api/Auth/RequestToken \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"consumer_key": "your_consumer_key",
"consumer_secret": "your_consumer_secret"
}'

Returns a Bearer token — attach it as Authorization: Bearer {token} on every subsequent request.

Demo credentials: Pesapal's public demo consumer key/secret (qkio1BGGYAXTu2JOfm7XSXNruoZsrqEW / osGQ364R49cXKeOYSpaOnT++rHs=) work against the demo URL above for early testing.

Register IPN URL

Endpoint: POST /api/URLSetup/RegisterIPN

Run once per environment. Returns an ipn_id — pass this as notification_id on every order you submit.

curl -X POST https://pay.pesapal.com/v3/api/URLSetup/RegisterIPN \
-H "Authorization: Bearer {access_token}" \
-H "Content-Type: application/json" \
-d '{
"ipn_notification_type": "POST",
"url": "https://payments.pesavoucher.com/api/v2/listen_pesapal.php"
}'

Get Registered IPNs

Endpoint: GET /api/URLSetup/GetIpnList

Lists all IPN URLs registered on your Pesapal account.

Submit Order Request

Endpoint: POST /api/Transactions/SubmitOrderRequest

curl -X POST https://pay.pesapal.com/v3/api/Transactions/SubmitOrderRequest \
-H "Authorization: Bearer {access_token}" \
-H "Content-Type: application/json" \
-d '{
"id": "ORD-2026-0417",
"currency": "KES",
"amount": "1500.00",
"description": "PesaVoucher Test Payment",
"callback_url": "https://yoursite.com/payment/complete",
"notification_id": "{ipn_id}",
"language": "EN",
"terms_and_conditions_id": "",
"billing_address": {
"phone_number": "254712345678",
"email_address": "test@pesavoucher.com",
"country_code": "KE",
"first_name": "Jane",
"middle_name": "",
"last_name": "Doe",
"line_1": "Nairobi",
"line_2": "",
"city": "Nairobi",
"state": "",
"postal_code": "",
"zip_code": ""
}
}'

Returns order_tracking_id and redirect_url — embed redirect_url in an iframe.

Get Transaction Status

Endpoint: GET /api/Transactions/GetTransactionStatus?orderTrackingId={order_tracking_id}

curl "https://pay.pesapal.com/v3/api/Transactions/GetTransactionStatus?orderTrackingId=9c5add4c-1234-5678-9abc-def012345678" \
-H "Authorization: Bearer {access_token}"

Returns payment_status_description — see the status table above. Use this to poll status directly if you're integrating with Pesapal yourself rather than relying on PesaVoucher's IPN forwarding.


Testing

  1. Register (or confirm PesaVoucher has already registered) your IPN URL
  2. Call Initiate Payment, embed the returned redirect_url in an iframe
  3. Complete a test payment using Pesapal's demo credentials/environment
  4. Confirm you receive a webhook/IPN update on your configured URL with COMPLETED status
  5. Test a failed/cancelled payment to confirm FAILED is handled correctly

Best Practices

  • Embed redirect_url in an iframe rather than opening it in a new tab — this matches Pesapal's intended checkout UX
  • Treat the IPN/webhook notification as your source of truth; the browser redirect is UX only
  • Store order_tracking_id alongside your own order_id for reconciliation
  • Handle all five payment_status_description values, including REVERSED
  • Confirm with support whether X-API-KEY / X-API-SECRET headers are required for initiate.php on your account
  • Never expose your Pesapal consumer_secret if you integrate directly