Repository navigation
feat: Daraja 3.0 disbursements (B2B and Business To Pochi) - #63
Merged
Merged
Conversation
Transcribed the success and failure result samples for Business Pay Bill, Business Buy Goods, B2C Account Top Up, Tax Remittance and Business To Pochi from the Daraja portal, repairing only the portal's invalid JSON (each fix is listed in the fixtures README and noted on its test). parseResult reads all ten without changes: B2B completion times become Dates, Top Up's numeric BillReferenceNumber is kept, and its valueless Occassion reference is skipped.
Daraja 3.0 brings business-to-business payments back as separate products. b2b.payBill pays a paybill from your shortcode: a private b2bRequest builds the shared B2B body (SenderIdentifierType and RecieverIdentifierType 4, Daraja's spelling kept) and sends it through initiatorRequest, so every problem is still reported in one ValidationError before anything is sent. accountReference is required (up to 13 characters); requester and occasion are optional.
Pays a till, merchant store or merchant head office from your shortcode (CommandID BusinessBuyGoods on the same B2B endpoint as Pay Bill). Unlike payBill, the account reference is optional; requester and occasion are optional too, and none of the three is sent when not given.
Moves money from your working account to a B2C shortcode's utility account (CommandID BusinessPayToBulk). The account reference and requester are optional, and Occassion is never sent: Top Up's parameter table doesn't include it.
Tax Remittance posts PayTaxToKRA to /mpesa/b2b/v1/remittax. KRA's shortcode 572572 is the only PartyB Daraja accepts, so the method sends it itself and takes no partyB. The account reference is the PRN KRA issues and is required; Requester and Occassion are never sent.
Business To Pochi has its own endpoint (/mpesa/b2pochi/v1/paymentrequest) but B2C's body and rules: InitiatorName, a generated or given OriginatorConversationID, Ksh 10 to 250 000 and 2 to 100 character remarks. pay and payToPochi now share one send helper; pay's commandId check runs first inside it, so the order of its validation issues is unchanged and its 20 existing tests pass as they were.
B2BApi, B2BPayBillInput, B2BBuyGoodsInput, B2BTopUpInput, B2BTaxInput and B2CPochiInput are exported from the package root, and the type test pins Mpesa['b2b'] and each new method's input and return type.
A new B2B page covers payBill, buyGoods, topUpB2C and remitTax with a field table each, the B2C page gains a Business To Pochi section, and every list of initiator APIs (configuration, certificates, callbacks, limits, exports, home page, README, migration table, the bug report dropdown and the API instructions) now includes them. The examples are mirrored in docs-examples.ts, so vp check type-checks them.
The partyB rule now runs only for the three methods that take one, rather than passing trivially for remitTax, and Top Up's and Tax's account reference limit and Buy Goods' requester and occasion rules get their own tests. The fixture comments now list the same hand fixes as the fixtures README, and the B2B JSDoc names the shortcode length and the requester formats.
One opt-in sandbox run on 2026-10-07 sent each method from the sandbox org shortcode through a tunnel. Daraja accepted all four B2B requests (ResponseCode 0) and posted their results within seconds, each 8006 because the shared test initiator is still locked. Business To Pochi got 401.002.01 twice (the SDK refreshes once): the sandbox app doesn't have that product. The redacted acknowledgements, the Pochi refusal and the four results are pinned, including that Buy Goods and Top Up results carry no BillReferenceNumber.
The migration guide's initiator and derived-field lists include B2B and Business To Pochi, the B2B page names the portal's org API roles and the requester formats, and its Results section says which balance field parseBalances splits and that only Pay Bill and Tax results echo the account reference (Buy Goods and Top Up didn't in the sandbox).
Daraja's error bodies carry a requestId trace ID that the fixture redaction kept; it is now masked like the conversation IDs, and the Business To Pochi capture is re-redacted. The B2B docs only claim what the sandbox run showed: Buy Goods didn't echo the account reference it was sent, and Top Up wasn't sent one.
Owner
Author
|
@claude review |
|
Claude finished @newtonmunene99's task in 21s —— View job Review of PR #63: Daraja 3.0 disbursementsI found no blocking issues. I read the source changes (
What works well
Minor suggestions (non-blocking)
Release
|
From the PR review: a test pins the order in which payBill reports every invalid field at once, and the B2B page says that Top Up and Tax Remittance ignore the fields they don't take when untyped JavaScript passes them.
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds the five Daraja 3.0 disbursement products, which all act through the initiator.
CommandIDb2b.payBill/mpesa/b2b/v1/paymentrequestBusinessPayBillb2b.buyGoods/mpesa/b2b/v1/paymentrequestBusinessBuyGoodsb2b.topUpB2C/mpesa/b2b/v1/paymentrequestBusinessPayToBulkb2b.remitTax/mpesa/b2b/v1/remittaxPayTaxToKRAb2c.payToPochi/mpesa/b2pochi/v1/paymentrequestBusinessPayToPochiHow it works
b2bRequestbuilt oninitiatorRequest. It sendsSenderIdentifierType/RecieverIdentifierType"4"(Daraja's spelling) and noOriginatorConversationID, and it reports every invalid field in oneValidationError.remitTaxalways sends KRA's572572and takes nopartyB.Occassion.payToPochiuses the B2C body and rules: a generatedOriginatorConversationID, Ksh 10 to 250 000. It shares one helper withb2c.pay, andpay's existing tests are unchanged.parseResult. The portal's success and failure samples for all five are now fixtures, and the parser reads them with no changes.Docs: a new B2B page (live after release) and a Business To Pochi section on the B2C page. The configuration, certificates, callbacks, limits, exports, home and migration pages, the README, the bug-report dropdown and the API instructions now include the new methods. The examples are type-checked through
docs-examples.ts.Live sandbox run (2026-10-07):
8006because the sharedtestapiinitiator is still locked.401.002.01: the sandbox app doesn't have that product.sandbox-captures.spec.ts. The fixture redaction now also masks the gateway'srequestId.Release: a minor changeset; the next version PR gives
4.0.0-alpha.1.Checks:
vp check,vp test(378 passed),vp pack,test:dist,lint:pkganddocs:buildall pass. A separate reviewer approved each phase; 39 of 40 mutations were killed, and the survivor makes no difference on the wire.