Pesapal (API 3.0) · Error reference
Pesapal API 3.0 Errors and Payment Statuses Explained
Pesapal API 3.0 reports a payment as one of four statuses (COMPLETED, FAILED, REVERSED or INVALID) from GetTransactionStatus, and reports rejected requests with an error object of type, code and message.
Have a response you don't understand? Paste it into the Payment Error Code Lookup and it finds every known code inside.
How Pesapal reports errors
- Rejected requests come back as JSON with an error object: {"type": "...", "code": "...", "message": "..."}. Pesapal's docs don't publish a list of the codes, so log the whole object.
- The payment outcome comes only from GET /api/Transactions/GetTransactionStatus: payment_status_description and status_code (0 INVALID, 1 COMPLETED, 2 FAILED, 3 REVERSED).
- The callback redirect (OrderNotificationType CALLBACKURL) and the IPN (IPNCHANGE) never carry the status. They only tell you which order to look up.
How sure is this?
Each code below is labelled by how well it is documented. All 10 codes on this page come from Pesapal's own documentation, linked under each one. Log the full response anyway: messages change.
Payment outcomes
The status values that tell you whether the customer paid.
COMPLETED Paid (status_code 1)
PaidSeen in: Status / callbackRetry: not neededIn the provider's docs
GetTransactionStatus returns payment_status_description Completed and status_code 1: the customer paid.
What to do
- Check that merchant_reference is your order and that amount and currency match, then fulfil the order once.
- Store confirmation_code: a refund needs it.
Sources: Pesapal API 3.0 docs: GetTransactionStatus
INVALID Not paid (status_code 0)
WaitingSeen in: Status / callbackRetry: No, fix the cause firstIn the provider's docs
status_code 0. Pesapal's docs list INVALID as one of the four statuses without defining it. It is not COMPLETED, so the order is not paid.
What to do
- Don't fulfil. Check again after the IPN or from a scheduled job, and expire the order if it never completes.
The docs give no definition for INVALID beyond the name and code. Treating it as "not paid yet, keep checking" is the safe reading: never fulfil on it, and never fail an order on it alone.
Sources: Pesapal API 3.0 docs: GetTransactionStatus
IPNCHANGE IPN: a status changed
Not known yetSeen in: CallbackRetry: Check the status before retryingIn the provider's docs
OrderNotificationType on an IPN call. Pesapal calls your registered IPN URL (GET or POST, as you registered it) with OrderTrackingId and OrderMerchantReference when a payment status changes. It does not include the status.
How to fix it
- Call GetTransactionStatus with the OrderTrackingId and settle from that. Never mark an order paid from the IPN itself.
Sources: Pesapal API 3.0 docs: SubmitOrderRequest
CALLBACKURL Customer redirected back
Not known yetSeen in: CallbackRetry: Check the status before retryingIn the provider's docs
OrderNotificationType when Pesapal sends the customer back to your callback_url, with OrderTrackingId and OrderMerchantReference in the query string. It does not include the status.
How to fix it
- Call GetTransactionStatus before showing "paid". If it isn't COMPLETED yet, show a "confirming your payment" page.
Sources: Pesapal API 3.0 docs: SubmitOrderRequest
Failure reasons
Why a payment did not go through.
FAILED Payment failed (status_code 2)
Not paidSeen in: Status / callbackRetry: Yes, as a new requestIn the provider's docs
status_code 2: the payment did not go through. description says why.
How to fix it
- Mark the order unpaid and let the customer try again with a new order request (a new id).
What to tell the customer
Your payment didn't go through. Please try again.
Sources: Pesapal API 3.0 docs: GetTransactionStatus
REVERSED Payment reversed (status_code 3)
Not paidSeen in: Status / callbackRetry: No, fix the cause firstIn the provider's docs
status_code 3: a payment was reversed.
How to fix it
- If you had marked the order paid, mark it reversed and stop or recover the goods or service. Look at the payment in your Pesapal dashboard.
Sources: Pesapal API 3.0 docs: GetTransactionStatus
Request errors
Returned straight away when the API rejects your request.
error object Request rejected (type, code, message)
Request errorSeen in: API responseRetry: No, fix the cause firstIn the provider's docs
When a call fails, Pesapal answers with a JSON error object of type, code and message. The docs don't list the codes.
How to fix it
- Log the whole object. Check the token (it lasts at most 5 minutes), the notification_id (register the IPN in the same environment), and that your order id uses only letters, numbers and - _ . : (max 50).
Successful GetTransactionStatus answers can also contain an error object whose fields are all null. Treat it as an error only when code or message is set.
Sources: Pesapal API 3.0 docs: API reference · Pesapal API 3.0 docs: authentication · Pesapal API 3.0 docs: SubmitOrderRequest
WaitingSeen in: API responseRetry: No, fix the cause firstIn the provider's docs
RefundRequest answered 200: the refund was received and is being processed. It is not complete: the merchant must approve it.
What to do
- Approve the refund in Pesapal. Only one refund is allowed per payment.
Sources: Pesapal API 3.0 docs: RefundRequest
Request errorSeen in: API responseRetry: No, fix the cause firstIn the provider's docs
RefundRequest answered 500: the refund was rejected. The message says why.
How to fix it
- Only COMPLETED payments can be refunded, once, in the same currency, up to the amount paid. Mobile money payments can only be refunded in full; cards in full or in part. Use the confirmation_code from GetTransactionStatus.
Sources: Pesapal API 3.0 docs: RefundRequest
Request errorSeen in: API responseRetry: No, fix the cause firstIn the provider's docs
CancelOrder answered 500: the order could not be cancelled.
How to fix it
- Only failed or pending payments can be cancelled, and only once. A processed payment can't be cancelled: refund it instead.
Sources: Pesapal API 3.0 docs: order cancellation
Handle every code in your code
Map each outcome code to one of four actions. Unknown codes fall back to "check the status", so a new or misspelled code never fulfils or cancels an order by accident.
// What to do with each Pesapal (API 3.0) outcome code.
// Unknown codes fall back to "check_status": never fulfil or fail an order on a code you don't recognise.
const ACTIONS = {
"COMPLETED": "fulfil", // Paid (status_code 1)
"FAILED": "mark_failed", // Payment failed (status_code 2)
"INVALID": "wait", // Not paid (status_code 0)
"REVERSED": "mark_failed", // Payment reversed (status_code 3)
"IPNCHANGE": "check_status", // IPN: a status changed
"CALLBACKURL": "check_status", // Customer redirected back
};
export function pesapalNextStep(code) {
const key = String(code ?? "").trim().toUpperCase().replace(/[\s-]+/g, "_");
return ACTIONS[key] ?? "check_status";
}
// Example:
// switch (pesapalNextStep(status.payment_status_description)) {
// case "fulfil": // verify amount, then mark the order paid (idempotently)
// case "mark_failed": // mark unpaid, show a retry button
// case "wait": // do nothing yet; a callback or your poller will follow
// case "check_status": // ask the status endpoint before deciding
// }
Frequently asked questions
What does Pesapal status INVALID mean?
INVALID (Not paid (status_code 0)): status_code 0. Pesapal's docs list INVALID as one of the four statuses without defining it. It is not COMPLETED, so the order is not paid. Don't fulfil. Check again after the IPN or from a scheduled job, and expire the order if it never completes.
What does Pesapal status IPNCHANGE mean?
IPNCHANGE (IPN: a status changed): OrderNotificationType on an IPN call. Pesapal calls your registered IPN URL (GET or POST, as you registered it) with OrderTrackingId and OrderMerchantReference when a payment status changes. It does not include the status. Call GetTransactionStatus with the OrderTrackingId and settle from that. Never mark an order paid from the IPN itself.
What does Pesapal status REVERSED mean?
REVERSED (Payment reversed (status_code 3)): status_code 3: a payment was reversed. If you had marked the order paid, mark it reversed and stop or recover the goods or service. Look at the payment in your Pesapal dashboard.
What does Pesapal error error object mean?
error object (Request rejected (type, code, message)): When a call fails, Pesapal answers with a JSON error object of type, code and message. The docs don't list the codes. Log the whole object. Check the token (it lasts at most 5 minutes), the notification_id (register the IPN in the same environment), and that your order id uses only letters, numbers and - _ . : (max 50).
What does Pesapal error RefundRequest 500 mean?
RefundRequest 500 (Refund rejected): RefundRequest answered 500: the refund was rejected. The message says why. Only COMPLETED payments can be refunded, once, in the same currency, up to the amount paid. Mobile money payments can only be refunded in full; cards in full or in part. Use the confirmation_code from GetTransactionStatus.
Integration guides
Full Pesapal integrations that handle these codes: Pesapal API 3.0 in Node.js, Laravel, Django, Next.js, Pesapal Request Builder.
Checked November 2026. Error codes change. If you see one that's missing or wrong, please let me know.