Get a transaction by confirmation code
const url = 'https://cybqa.pesapal.com/pesapalv3/api/Transactions/QueryStatusByConfirmationCode?confirmationCode=example';const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request GET \ --url 'https://cybqa.pesapal.com/pesapalv3/api/Transactions/QueryStatusByConfirmationCode?confirmationCode=example' \ --header 'Authorization: Bearer <token>'Returns the same transaction as getTransactionStatus, keyed by the
payment’s confirmation code.
The two do not agree on every field. For the same card payment,
getTransactionStatus reports payment_method: "Visa" while this
endpoint reports "Card", and call_back_url and status are null
here. Use one endpoint consistently for reporting.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Query Parameters
Section titled “Query Parameters”The confirmation_code of a completed payment.
Responses
Section titled “Responses”Returned for both success and failure.
object
1 is a completed payment, 2 is a failed one. 0 and 3 are
sometimes cited but have never been observed.
No fixed format. A card payment returns 22 numeric digits, a completed M-Pesa payment returns the alphanumeric receipt code the customer also gets by SMS, and a failed one returns a short numeric value.
It cannot be stored as a number: UI76G5D93D is not numeric, and the
card form exceeds what a 64-bit float represents exactly. Type it as
a string with no assumed length or character set.
Differs between lookup endpoints for the same payment.
The masked card number or the phone number used.
A human-readable outcome on a card payment, for example
Transaction successfully processed. Null on a mobile money payment
whether it completed or failed, so it cannot be relied on to be
present.
East Africa Time with no timezone designator, unlike created_date
on an IPN registration, which is UTC. Parsing this as UTC shifts every
payment by three hours.
Empty on a completed payment. On a failed one it sometimes names the
reason, for example request_terminated_by_user when the customer
declined a mobile money prompt, and is sometimes still empty. Read
status_code for the outcome and treat this as optional detail.
On a successful lookup this is an object whose fields are all null,
not null itself, so a truthiness check misreports success as
failure.
object
An application error, returned with HTTP 200.
object
A populated error. Every field is present and non-null.
object
Mostly snake_case, but not consistently: InvalidIpnId is
PascalCase. Compare exactly.
Multiple validation errors arrive pipe-delimited in one string, and malformed JSON produces leading empty segments.
Usually "500". Never matches the HTTP status.
Example
{ "status_code": 1, "payment_status_description": "Completed", "confirmation_code": "7884396530786173704004", "created_date": "2026-09-03T15:47:34.567"}