Skip to content

Business to Business

All three B2B operations share one endpoint and differ only by CommandID.

POST mpesa/b2b/v1/paymentrequest

Money moves from your MMF/Working account to the recipient’s account.

// To a pay bill — credits their utility account
Daraja::b2b()->payBill(
receiverShortCode: '123456',
amount: 15000,
accountReference: 'ACC-88',
remarks: 'October supply',
);
// To a till or merchant store — credits their merchant account
Daraja::b2b()->buyGoods('654321', 4500);

accountReference is capped at 13 characters.

Both accept an optional requester, the mobile number of the consumer you are paying on behalf of:

Daraja::b2b()->payBill('123456', 2000, 'ACC-88', requester: '0712345678');

Loads funds into one of your own B2C short codes so it can disburse. This is the API answer to “my B2C says insufficient balance but the money is in Working”.

Daraja::b2b()->accountTopUp(
b2cShortCode: '600979',
amount: 100000,
accountReference: 'TOPUP-11',
);

Safaricom accepts only type 4 on both sides of this API, whatever the destination. The package hard-codes it, so nothing is derived from your configured initiator.type here.

public function handle(ResultReceived $event): void
{
if ($event->type !== 'b2b') {
return;
}
$event->result->successful();
$event->result->receipt();
}

Balance values in B2B results are not JSON. They arrive either pipe-delimited or as a Java-style map literal:

Working Account|KES|346568.83|6186.83|340382.00|0.00
{Amount={CurrencyCode=KES, MinimumAmount=618683, BasicAmount=6186.83}}

The first form parses with AccountBalances; the second is exposed raw through $event->result->parameters.