Business Pay Bill
Pay from a business account directly into another organization's Pay Bill number, on your own behalf or a customer's.
Endpoint
https://sandbox.safaricom.co.ke/mpesa/b2b/v1/paymentrequestOverview
Pays a Pay Bill number or Pay Bill store, moving money from your MMF/Working account into the recipient's Utility account. Can be used to pay on behalf of a consumer/requester.
Shares its endpoint with Business Buy
Goods, B2C Account Top
Up, and Tax
Remittance. CommandID is what
distinguishes them.
Request
{
"Initiator": "API_Usename",
"SecurityCredential": "FKXl/KPzT8hFOnozI+unz7mXDgTRbrlrZ+C1Vblxpbz7jliLAFa0E/…../uO4gzUkABQuCxAeq+0Hd0A==",
"Command ID": "BusinessPayBill",
"SenderIdentifierType": "4",
"RecieverIdentifierType": "4",
"Amount": "239",
"PartyA": "123456",
"PartyB": "000000",
"AccountReference": "353353",
"Requester": "254700000000",
"Remarks": "OK",
"QueueTimeOutURL": "http://0.0.0.0:0000/ResultsListener.php",
"ResultURL": "http://0.0.0.0:8888/TimeOutListener.php"
}Defect in the source material
Safaricom's own sample request body writes the field as "Command ID", with a
space, which is not valid as a JSON key matching the documented field name
CommandID used everywhere else, including in this same API's parameter
table. The parameter table version, CommandID, is what's used in the field
reference below and is almost certainly what the live endpoint expects; the
sample body is reproduced above exactly as Safaricom wrote it.
| Field | Description | Sample value |
|---|---|---|
CommandID | Only BusinessPayBill for this API. | BusinessPayBill |
Initiator | API operator username, needs the Org Business Pay Bill API initiator role. | Username |
SecurityCredential | Encrypted initiator password. | (encrypted string) |
PartyA | Your short code, debited. | 123454 (5 to 6 digits) |
SenderIdentifierType | Only 4 is allowed. | 4 |
PartyB | Recipient short code, credited. | 000000 |
RecieverIdentifierType (sic) | Only 4 is allowed. | 4 |
Requester | Optional, consumer's mobile number if paying on their behalf. | 254000000000 |
Amount | Transaction amount. | 300 |
AccountReference | Up to 13 characters. | ACC#03929/4yu |
Remarks | Up to 100 characters. | Free text |
QueueTimeOutURL / ResultURL | Timeout and result callback URLs. | https://domain:port/path |
Occassion (sic) | Optional. | Free text |
Response
{
"OriginatorConversationID": "5118-111210482-1",
"ConversationID": "AG_20230420_2010759fd5662ef6d054",
"ResponseCode": "0",
"ResponseDescription": "Accept the service request successfully."
}Defect in the source material
Safaricom's own response parameter table spells the first field
OriginatorConverstionID; the sample response body above spells it correctly.
Both come directly from Safaricom's documentation.
Successful result callback
{
"Result": {
"ResultType": "0",
"ResultCode": "0",
"ResultDesc": "The service request is processed successfully",
"OriginatorConversationID": "626f6ddf-ab37-4650-b882-b1de92ec9aa4",
"ConversationID": "12345677dfdf89099B3",
"TransactionID": "QKA81LK5CY",
"ResultParameters": {
"ResultParameter": [
{
"Key": "DebitAccountBalance",
"Value": "{Amount={CurrencyCode=KES, MinimumAmount=618683, BasicAmount=6186.83}}"
},
{ "Key": "Amount", "Value": "190.00" },
{
"Key": "DebitPartyAffectedAccountBalance",
"Value": "Working Account|KES|346568.83|6186.83|340382.00|0.00"
},
{ "Key": "TransCompletedTime", "Value": "20221110110717" },
{ "Key": "DebitPartyCharges", "Value": "" },
{
"Key": "ReceiverPartyPublicName",
"Value": "000000 - Biller Company"
},
{ "Key": "Currency", "Value": "KES" },
{
"Key": "InitiatorAccountCurrentBalance",
"Value": "{Amount={CurrencyCode=KES, MinimumAmount=618683, BasicAmount=6186.83}}"
}
]
},
"ReferenceData": {
"ReferenceItem": [
{ "Key": "BillReferenceNumber", "Value": "19008" },
{
"Key": "QueueTimeoutURL",
"Value": "http://172.31.234.68:8888/Listener.php"
}
]
}
}
}Defect in the source material
Safaricom's sample writes the ReceiverPartyPublicName value as "000000– Biller Companty", an em dash instead of a hyphen and a misspelling of
"Company." Corrected above to "000000 - Biller Company"; the actual returned
value hasn't been independently confirmed.
Unsuccessful result callback
{
"Result": {
"ResultType": 0,
"ResultCode": 2001,
"ResultDesc": "The initiator information is invalid.",
"OriginatorConversationID": "12337-23509183-5",
"ConversationID": "AG_20200120_0000657265d5fa9ae5c0",
"TransactionID": "OAK0000000",
"ResultParameters": {
"ResultParameter": { "Key": "BOCompletedTime", "Value": 20200120164825 }
},
"ReferenceData": {
"ReferenceItem": {
"Key": "QueueTimeoutURL",
"Value": "https://internalapi.safaricom.co.ke/mpesa/abresults/v1/submit"
}
}
}
}Common failure codes documented across the B2B family (this API, Business Buy Goods, B2C Account Top Up, and Tax Remittance) include 2001 (initiator information invalid), account and product-assignment rule declines, and security credential lock. Safaricom's documentation doesn't publish a distinct, complete result-code table specific to Business Pay Bill beyond the sample shown above.
Testing and Go Live
Daraja Simulator: create a test app with the Business Pay Bill product attached.
Postman: token from the sandbox OAuth endpoint, then call the endpoint above.
Going live follows the same Organization Portal & Go Live path as the rest of the B2B/B2C family, requiring the Business Paybill Org API Initiator role on the operator you use as Initiator.