Daraja SDK Logomark
Daraja SDK
B2B & Tax Transfers

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/paymentrequest

Overview

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.

FieldDescriptionSample value
CommandIDOnly BusinessPayBill for this API.BusinessPayBill
InitiatorAPI operator username, needs the Org Business Pay Bill API initiator role.Username
SecurityCredentialEncrypted initiator password.(encrypted string)
PartyAYour short code, debited.123454 (5 to 6 digits)
SenderIdentifierTypeOnly 4 is allowed.4
PartyBRecipient short code, credited.000000
RecieverIdentifierType (sic)Only 4 is allowed.4
RequesterOptional, consumer's mobile number if paying on their behalf.254000000000
AmountTransaction amount.300
AccountReferenceUp to 13 characters.ACC#03929/4yu
RemarksUp to 100 characters.Free text
QueueTimeOutURL / ResultURLTimeout 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.

On this page