Request an access token
const url = 'https://cybqa.pesapal.com/pesapalv3/api/Auth/RequestToken';const options = { method: 'POST', headers: {'Content-Type': 'application/json'}, body: '{"consumer_key":"example","consumer_secret":"example"}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://cybqa.pesapal.com/pesapalv3/api/Auth/RequestToken \ --header 'Content-Type: application/json' \ --data '{ "consumer_key": "example", "consumer_secret": "example" }'Exchanges a consumer key and secret for a bearer token valid for 60 minutes. Cache the token rather than requesting one per call.
Content-Type: application/json is mandatory. Omitting it returns
HTTP 415 with a plain-text message rather than the usual error body.
Request Bodyrequired
Section titled “Request Bodyrequired”object
Examplegenerated
{ "consumer_key": "example", "consumer_secret": "example"}Responses
Section titled “Responses”Returned for both success and failure. A successful response carries
token; a failed one carries error.
object
A JWT. Its exp claim is an integer and easier to parse than expiryDate.
UTC, with a Z and seven fractional-second digits. That precision is
rejected by some strict parsers, including Python’s
datetime.fromisoformat before 3.11.
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.
Examples
Token issued
{ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "expiryDate": "2026-09-03T12:08:08.5585879Z", "error": null, "status": "200", "message": "Request processed successfully"}Wrong key or secret
{ "error": { "error_type": "api_error", "code": "invalid_consumer_key_or_secret_provided", "message": "Invalid Access Credentials provided" }, "status": "500"}The Content-Type header was missing.
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"}