Skip to content

Testing

Pesapal runs a sandbox that mirrors production. Only the host differs:

Environment Base URL
Sandbox https://cybqa.pesapal.com/pesapalv3/api
Production https://pay.pesapal.com/v3/api

Paths, request bodies and responses are identical, so pointing an integration at production is a one-line change.

Pesapal publishes sandbox credentials openly at the demo keys page. You do not need an account to start.

Use these on the hosted payment page. Any name, address and future expiry works alongside them.

Brand Number Expiry CVV
Visa 4761 7390 0101 0010 07/28 123
MasterCard 5200 0000 0000 0114 07/28 123
Amex 3400 0000 0003 961 07/28 1234
Brand Number Expiry CVV
Visa 4000 0000 0000 1091 07/28 123
MasterCard 5200 0000 0000 0007 07/28 123
Brand Number Expiry CVV
Visa 4000 0000 0000 1018 07/28 123

You can find these card details on the Test Payments page.

That has a knock-on effect worth planning around: you cannot test your failure-handling path end to end. status_code values other than 1 have never been observed, so any branch you write for them is untested code.

Two ways to work around it:

  • Unit test your handler against a hand-written failed response rather than a live one.
  • Test the pending path instead, which is easy and is where most bugs live. Create an order and query it without paying. See an unpaid order comes back as an error.

Pesapal only sends an IPN when a payment actually completes, so you need a publicly reachable URL before you can see one.

  1. Open webhook.site and copy your unique URL. It gives you a public endpoint and logs the full request, including query parameters.

  2. Register it with RegisterIPN and keep the ipn_id.

  3. Create an order with that notification_id, open its redirect_url, and pay with a test card.

  4. Refresh webhook.site. The notification arrives as a GET with three query parameters and no body.

When you move to testing against your own server, a tunnel such as ngrok or cloudflared exposes localhost publicly.

  1. Swap the base URL to https://pay.pesapal.com/v3/api.

  2. Swap your consumer key and secret for your own, from the Pesapal dashboard. Keep them out of source control.

  3. Register your production IPN URL. Registrations do not carry across environments, and the ipn_id will be different.

  4. Verify your IPN endpoint is actually reachable from the public internet. Pesapal does not check this at registration, so a wrong URL fails silently.

  5. Confirm your first real transaction end to end before taking live traffic.