Core Concepts
Callback URL Validation
The rules the SDK enforces on every callBackURL, confirmationUrl, validationUrl, resultURL, and queueTimeOutURL.
Every endpoint that accepts a webhook URL mpesaExpress.push()'s callBackURL, c2b.registerUrl()'s confirmationUrl/validationUrl, and b2cTopUp.topUp()'s queueTimeOutURL/resultURL runs the same validateCallbackUrl() check before the request is sent.
What gets checked, in order
- Presence must be a non-empty string
- Valid URL must parse with the
URLconstructor and usehttp:orhttps: - HTTPS in production if
environment: 'production',http://URLs are rejected outright - No banned keywords the hostname+path can't contain
mpesa,safaricom,exec, orsql(case-insensitive). These are local SDK validation rules. - No configured tunneling hosts
ngrok.io,ngrok-free.app,ngrok.app,mockbin.org,requestbin.com, andrequestbin.net(and their subdomains) are rejected by the SDK.
// Throws INVALID_CALLBACK_URL: "callBackURL contains a disallowed keyword
// (\"mpesa\")."
await daraja.stkPush({
// ...
callBackURL: "https://example.com/mpesa-callback",
});Local development
The SDK rejects the tunnel hosts listed above. Use a public domain or a tunnel host that is not on the SDK's blocklist, then verify the callback behavior in the Daraja environment you are targeting.
Which fields this applies to
| Endpoint | Fields validated |
|---|---|
mpesaExpress.push() | callBackURL |
c2b.registerUrl() | confirmationUrl, validationUrl |
b2cTopUp.topUp() | queueTimeOutURL, resultURL |
There is currently no config flag to relax these checks. Rename a route or use a different hostname when a legitimate URL matches a blocked value.