Daraja SDK Logomark
Daraja SDK
B2B & Tax Transfers

B2B Express CheckOut

Trigger a USSD prompt asking a fellow merchant's till operator to pay into your paybill.

Also referred to as B2B UssdPush to Till. It lets a merchant (the "vendor") prompt another merchant's till operator to authorize a payment from their till into the vendor's Pay Bill.

Endpoint

https://sandbox.safaricom.co.ke/v1/ussdpush/get-msisdn

How it works

  1. The vendor sends the USSD push request via Daraja.
  2. Daraja triggers an STK-style push to the paying merchant's till operator.
  3. The operator enters their Operator ID and M-PESA PIN to authorize.
  4. M-PESA credits the vendor and debits the merchant.
  5. Daraja sends a callback with the outcome to the vendor's callbackUrl.

Authentication happens at the Apigee/Daraja layer, the same as any other product: attach B2B Express Checkout to your app to get a Consumer Key and Consumer Secret.

Request

{
  "primaryShortCode": "000001",
  "receiverShortCode": "000002",
  "amount": "100",
  "paymentRef": "paymentRef",
  "callbackUrl": "http://..../result",
  "partnerName": "Vendor",
  "RequestRefID": "{{random Unique Identifer For Each Request}}"
}
FieldDescriptionTypeSample value
primaryShortCodeThe debit party: the paying merchant's Till/short code.Number000001
receiverShortCodeThe credit party: the vendor's Pay Bill receiving the funds.Number000002
amountAmount to be sent.Number100
paymentRefReference shown to the paying merchant.AlphanumericpaymentRef
callbackUrlWhere the vendor receives the outcome.URLhttp://..../result
partnerNameVendor's friendly name, as shown to the merchant.StringVendor
RequestRefID (also documented as RequestRefId)A random unique ID for tracing the request end to end.Alphanumeric550e8400-e29b-41d4-a716-446655440000

Defect in the source material

Safaricom's own documentation is inconsistent about the casing of this last field, writing RequestRefID in the sample request and RequestRefId in the parameter table directly below it. Both are reproduced here rather than picking one, since it isn't clear from the documentation alone which casing the live endpoint actually expects, and this hasn't yet been confirmed against a sandbox call.

Acknowledgment response

{
  "code": "0",
  "status": "USSD Initiated Successfully"
}
FieldDescriptionSample value
resultCode0 for success, 4001 for customer-cancelled.0
resultDescriptionReason the push wasn't finalized, where applicable.User cancelled transaction
amountAmount initiated.71
requestIdYour original request identifier.404e1aec-19e0-4ce3-973d-bd92e94c8021
statusSUCCESS or FAILED.SUCCESS
transactionIdM-PESA receipt number, present only on success.RDQ01NFT1Q

Defect in the source material

Safaricom's own response parameter table lists resultDescription twice, once described as the failure reason and again, two rows later, described as if it held the same value as requestId. The acknowledgment sample itself only shows code and status; the table describes a different, larger set of fields (resultCode, amount, requestId, status, transactionId) that don't appear in that sample at all. Both are reproduced as documented rather than reconciled, since which fields the live endpoint actually returns hasn't been independently confirmed.

Merchant prompt text

The paying merchant sees a prompt along the lines of:

You are about to send Ksh {{amount}} to {{Vendor Friendly Name}} for payment reference: {{AccountNumber/BillReference}}.

They're then asked for their Operator ID, then their operator PIN, and shown a confirmation before the amount is deducted.

Callback payloads

Both a failed USSD push (before the merchant even responds) and a completed M-PESA transaction (after they do) result in a callback to the vendor's callbackUrl.

Cancelled

{
  "resultCode": "4001",
  "resultDesc": "User cancelled transaction",
  "requestId": "c2a9ba32-9e11-4b90-892c-7bc54944609a",
  "amount": "71.0",
  "paymentReference": "MAndbubry3hi"
}

Successful

{
  "resultCode": "0",
  "resultDesc": "The service request is processed successfully.",
  "amount": "71.0",
  "requestId": "404e1aec-19e0-4ce3-973d-bd92e94c8021",
  "resultType": "0",
  "conversationID": "AG_20230426_2010434680d9f5a73766",
  "transactionId": "RDQ01NFT1Q",
  "status": "SUCCESS"
}
FieldDescription
ResultCode0 for success; see Error Codes for failures.
ConversationId / OriginatorConversationIdIdentifiers returned by M-PESA and the API proxy respectively.
TransactionIDM-PESA transaction ID. A generic placeholder is sent for some failure scenarios.
ResultParameters / ReferenceDataExtra key-value transaction detail and reference data, in the same shape used across the B2B/B2C family.

Error codes

CodeCauseFix
4104Missing Nominated Number, the number the push is triggered fromProvide the nominated number.
4102Merchant KYC failureProvide valid KYC.
4201USSD network errorRetry on a stable network.
4203USSD exception errorRetry on a stable network.

Organization operators

Safaricom's documentation notes that an M-PESA short code can have multiple operators, each tied to a preferred MSISDN. Transactions from a given operator are deducted from the associated till, and the solution documented here is limited to the operator whose number is set as the Nominated Number under Organization Details on the M-PESA Web Portal. Access to that portal is granted automatically once a short code is registered.

Untested

The Daraja documentation for this API, as supplied for this reference, does not include Postman/simulator testing steps, error-table completeness, or a Go Live section in the same shape as the other B2B/B2C APIs. What's reproduced above is everything Safaricom's own page for this API documents; nothing has been added to fill the gap, and none of it has yet been exercised against the sandbox for this reference.

On this page