Get a transaction by tracking id
const url = 'https://cybqa.pesapal.com/pesapalv3/api/Transactions/GetTransactionStatus?orderTrackingId=2489E9AD-2EE2-8E00-8EC9-32D5F69181C0';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/GetTransactionStatus?orderTrackingId=2489E9AD-2EE2-8E00-8EC9-32D5F69181C0' \ --header 'Authorization: Bearer <token>'Returns the state of a payment.
An order that exists but has not been paid returns an error, with
code payment_details_not_found and the message Pending Payment. The
same code is returned for an order that does not exist, where the message
is Payment details not found instead, so only the message separates
them.
On success, error is an object whose fields are all null rather than
null itself, so a truthiness check on error reports a completed
payment as a failure. Read status_code instead.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Query Parameters
Section titled “Query Parameters”The order_tracking_id returned when the order was created.
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"}The orderTrackingId parameter was omitted entirely.
Returned by HTTP 404, 405 and 415, before the request reaches the application. Carries a plain-text message and no error object.
object
Examplegenerated
{ "message": "example"}