pesafy 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,837 @@
1
+ import { C as AccountBalanceRequest, D as MpesaConfig, E as Environment, O as TransactionStatusRequest, S as B2BExpressCheckoutResponse, _ as B2CRequest, a as ReversalResponse, c as C2BRegisterUrlRequest, d as C2BSimulateResponse, h as B2CDisbursementResponse, i as ReversalRequest, j as IdempotencyManager, k as TransactionStatusResponse, l as C2BRegisterUrlResponse, m as B2CDisbursementRequest, n as TaxRemittanceResponse, t as TaxRemittanceRequest, u as C2BSimulateRequest, v as B2CResponse, w as AccountBalanceResponse, x as B2BExpressCheckoutRequest } from "./types.js";
2
+
3
+ //#region src/mpesa/stk-push/types.d.ts
4
+ /**
5
+ * src/mpesa/stk-push/types.ts
6
+ *
7
+ * Types, constants, and helpers for the M-PESA STK Push (M-PESA Express) API.
8
+ *
9
+ * Daraja docs:
10
+ * STK Push → POST /mpesa/stkpush/v1/processrequest
11
+ * STK Query → POST /mpesa/stkpushquery/v1/query
12
+ */
13
+ type TransactionType = 'CustomerPayBillOnline' | 'CustomerBuyGoodsOnline';
14
+ interface StkPushRequest {
15
+ /**
16
+ * Transaction amount in KES.
17
+ * Min: {@link STK_PUSH_LIMITS.MIN_AMOUNT} (KES 1)
18
+ * Max: {@link STK_PUSH_LIMITS.MAX_AMOUNT} (KES 250 000)
19
+ * Must round to a whole number ≥ 1.
20
+ * Daraja field: `Amount`
21
+ */
22
+ amount: number;
23
+ /**
24
+ * Phone number sending the money. Format: 2547XXXXXXXX.
25
+ * Must be a valid Safaricom M-PESA number.
26
+ * Daraja fields: `PartyA`, `PhoneNumber`
27
+ */
28
+ phoneNumber: string;
29
+ /**
30
+ * URL where Safaricom will POST the callback result.
31
+ * Must be publicly accessible (use ngrok/localtunnel for local dev).
32
+ * Daraja field: `CallBackURL`
33
+ */
34
+ callbackUrl: string;
35
+ /**
36
+ * Alpha-numeric reference shown to customer in the USSD prompt.
37
+ * Truncated to max 12 characters before sending.
38
+ * Daraja field: `AccountReference`
39
+ */
40
+ accountReference: string;
41
+ /**
42
+ * Additional description for the transaction.
43
+ * Truncated to max 13 characters before sending.
44
+ * Daraja field: `TransactionDesc`
45
+ */
46
+ transactionDesc: string;
47
+ /**
48
+ * Business shortcode — Paybill number or HO/Store number for Till.
49
+ * Daraja field: `BusinessShortCode`
50
+ */
51
+ shortCode: string;
52
+ /**
53
+ * Passkey used to generate the Password.
54
+ * Sandbox: from Daraja simulator test data.
55
+ * Production: emailed after Go Live.
56
+ */
57
+ passKey: string;
58
+ /**
59
+ * "CustomerPayBillOnline" (default) for Paybill.
60
+ * "CustomerBuyGoodsOnline" for Till Numbers.
61
+ * Daraja field: `TransactionType`
62
+ */
63
+ transactionType?: TransactionType;
64
+ /**
65
+ * Credit party receiving funds.
66
+ * - CustomerPayBillOnline → defaults to `shortCode`
67
+ * - CustomerBuyGoodsOnline → set to the Till Number
68
+ * Daraja field: `PartyB`
69
+ */
70
+ partyB?: string;
71
+ }
72
+ /**
73
+ * Synchronous acknowledgement returned immediately after STK Push submission.
74
+ * This is NOT the payment result — the result arrives via callback.
75
+ *
76
+ * Daraja endpoint: POST /mpesa/stkpush/v1/processrequest
77
+ */
78
+ interface StkPushResponse {
79
+ /** Global unique identifier for the submitted payment request */
80
+ MerchantRequestID: string;
81
+ /** Global unique identifier for the checkout transaction — use this for STK Query */
82
+ CheckoutRequestID: string;
83
+ /**
84
+ * "0" = request accepted successfully.
85
+ * Any other value = submission error.
86
+ */
87
+ ResponseCode: string;
88
+ /** Human-readable submission status */
89
+ ResponseDescription: string;
90
+ /** Message shown to customer on their device */
91
+ CustomerMessage: string;
92
+ }
93
+ /**
94
+ * Parameters for querying the status of a previously initiated STK Push.
95
+ *
96
+ * Daraja endpoint: POST /mpesa/stkpushquery/v1/query
97
+ */
98
+ interface StkQueryRequest {
99
+ /** `CheckoutRequestID` from the STK Push response */
100
+ checkoutRequestId: string;
101
+ shortCode: string;
102
+ passKey: string;
103
+ }
104
+ /**
105
+ * Response from the STK Query API.
106
+ *
107
+ * Note: `ResultCode` is documented as "Numeric" by Daraja.
108
+ * The Daraja JSON example shows it as a string (`"ResultCode": "0"`),
109
+ * but actual API responses return a number. Typed as `number` here.
110
+ * Use {@link STK_RESULT_CODES} constants for comparisons.
111
+ */
112
+ interface StkQueryResponse {
113
+ /** "0" = request accepted. Not the final payment status. */
114
+ ResponseCode: string;
115
+ /** Submission status message */
116
+ ResponseDescription: string;
117
+ /** Unique identifier for the merchant request */
118
+ MerchantRequestID: string;
119
+ /** Unique identifier for the checkout transaction */
120
+ CheckoutRequestID: string;
121
+ /**
122
+ * Payment processing status code.
123
+ * See {@link STK_RESULT_CODES} for all documented values:
124
+ * 0 → success
125
+ * 1 → insufficient balance
126
+ * 1032 → cancelled by user
127
+ * 1037 → phone unreachable
128
+ * 2001 → wrong PIN
129
+ */
130
+ ResultCode: number;
131
+ /** Human-readable description of the result */
132
+ ResultDesc: string;
133
+ }
134
+ //#endregion
135
+ //#region src/utils/errors/index.d.ts
136
+ /**
137
+ * Pesafy error types — single source of truth.
138
+ *
139
+ * All codes map to a specific failure category so callers can handle
140
+ * them without string-matching on the message.
141
+ */
142
+ declare const ERROR_CODES: readonly ["AUTH_FAILED", "INVALID_CREDENTIALS", "INVALID_PHONE", "ENCRYPTION_FAILED", "VALIDATION_ERROR", "API_ERROR", "HTTP_ERROR", "NETWORK_ERROR", "REQUEST_FAILED", "INVALID_RESPONSE", "TIMEOUT", "RATE_LIMITED", "INSUFFICIENT_FUNDS", "TRANSACTION_FAILED", "DUPLICATE_REQUEST", "IDEMPOTENCY_ERROR"];
143
+ type ErrorCode = (typeof ERROR_CODES)[number];
144
+ interface PesafyErrorOptions {
145
+ code: ErrorCode;
146
+ message: string;
147
+ /** HTTP status code from Daraja (if applicable) */
148
+ statusCode?: number;
149
+ /** Raw Daraja response body (for debugging) */
150
+ response?: unknown;
151
+ /** Underlying caught error (network, crypto, etc.) */
152
+ cause?: unknown;
153
+ /** Daraja requestId from the error envelope */
154
+ requestId?: string;
155
+ /** Whether this error is retryable */
156
+ retryable?: boolean;
157
+ }
158
+ declare class PesafyError extends Error {
159
+ readonly code: ErrorCode;
160
+ readonly statusCode: number | undefined;
161
+ readonly response: unknown;
162
+ readonly requestId: string | undefined;
163
+ readonly cause: unknown;
164
+ readonly retryable: boolean;
165
+ constructor(options: PesafyErrorOptions);
166
+ /** Returns true if this is a validation error (user bug — do not retry) */
167
+ get isValidation(): boolean;
168
+ /** Returns true if this is an auth error */
169
+ get isAuth(): boolean;
170
+ toJSON(): {
171
+ name: string;
172
+ code: "AUTH_FAILED" | "INVALID_CREDENTIALS" | "INVALID_PHONE" | "ENCRYPTION_FAILED" | "VALIDATION_ERROR" | "API_ERROR" | "HTTP_ERROR" | "NETWORK_ERROR" | "REQUEST_FAILED" | "INVALID_RESPONSE" | "TIMEOUT" | "RATE_LIMITED" | "INSUFFICIENT_FUNDS" | "TRANSACTION_FAILED" | "DUPLICATE_REQUEST" | "IDEMPOTENCY_ERROR";
173
+ message: string;
174
+ statusCode: number | undefined;
175
+ requestId: string | undefined;
176
+ retryable: boolean;
177
+ };
178
+ }
179
+ //#endregion
180
+ //#region src/types/branded.d.ts
181
+ /**
182
+ * A discriminated union result — either Ok<T> or Err<E>.
183
+ * Prefer this over throwing in application-level code.
184
+ *
185
+ * @example
186
+ * const result = await mpesa.stkPushSafe({ ... });
187
+ * if (result.ok) {
188
+ * console.log(result.data.CheckoutRequestID);
189
+ * } else {
190
+ * console.error(result.error.code, result.error.message);
191
+ * }
192
+ */
193
+ type Result<T, E = PesafyError> = {
194
+ readonly ok: true;
195
+ readonly data: T;
196
+ } | {
197
+ readonly ok: false;
198
+ readonly error: E;
199
+ };
200
+ //#endregion
201
+ //#region src/mpesa/b2b-buy-goods/types.d.ts
202
+ /**
203
+ * src/mpesa/b2b-buy-goods/types.ts
204
+ *
205
+ * Strictly aligned with Safaricom Daraja Business Buy Goods API documentation.
206
+ * Endpoint: POST /mpesa/b2b/v1/paymentrequest
207
+ * CommandID: "BusinessBuyGoods"
208
+ *
209
+ * Moves money from your MMF/Working account to the recipient's merchant account
210
+ * (till number, merchant store number, or Merchant HO).
211
+ * SenderIdentifierType and RecieverIdentifierType are always "4" per docs.
212
+ */
213
+ /**
214
+ * The only CommandID supported by the Business Buy Goods API.
215
+ * Docs: "For this API use BusinessBuyGoods only"
216
+ */
217
+ type B2BBuyGoodsCommandID = 'BusinessBuyGoods';
218
+ /**
219
+ * Request payload for Business Buy Goods.
220
+ *
221
+ * Daraja payload shape:
222
+ * {
223
+ * "Initiator": "API_Username",
224
+ * "SecurityCredential": "FKX1/KPzT8hFO...",
225
+ * "CommandID": "BusinessBuyGoods",
226
+ * "SenderIdentifierType": "4",
227
+ * "RecieverIdentifierType": "4",
228
+ * "Amount": "239",
229
+ * "PartyA": "123456",
230
+ * "PartyB": "000000",
231
+ * "AccountReference": "353353",
232
+ * "Requester": "254700000000",
233
+ * "Remarks": "OK",
234
+ * "QueueTimeOutURL": "https://...",
235
+ * "ResultURL": "https://...",
236
+ * "Occassion": ""
237
+ * }
238
+ */
239
+ interface B2BBuyGoodsRequest {
240
+ /**
241
+ * Transaction type. Must be "BusinessBuyGoods".
242
+ * Daraja field: CommandID
243
+ */
244
+ commandId: B2BBuyGoodsCommandID;
245
+ /**
246
+ * Transaction amount in KES. Must be a whole number ≥ 1.
247
+ * Daraja field: Amount (sent as string per API spec)
248
+ */
249
+ amount: number;
250
+ /**
251
+ * Your shortcode from which money will be deducted.
252
+ * SenderIdentifierType is always "4" (Organisation ShortCode) per docs.
253
+ * Daraja field: PartyA
254
+ */
255
+ partyA: string;
256
+ /**
257
+ * The till number / merchant store number / Merchant HO to which money is moved.
258
+ * RecieverIdentifierType is always "4" (Organisation ShortCode) per docs.
259
+ * Daraja field: PartyB
260
+ */
261
+ partyB: string;
262
+ /**
263
+ * The account number associated with the payment (up to 13 characters).
264
+ * Daraja field: AccountReference
265
+ */
266
+ accountReference: string;
267
+ /**
268
+ * Optional. The consumer's mobile number on whose behalf you are paying.
269
+ * Format: 254XXXXXXXXX
270
+ * Daraja field: Requester
271
+ */
272
+ requester?: string;
273
+ /**
274
+ * Any additional information for the transaction.
275
+ * Daraja field: Remarks
276
+ */
277
+ remarks?: string;
278
+ /**
279
+ * URL Safaricom calls with the final async result after processing.
280
+ * Must be publicly accessible. HTTPS required in production.
281
+ * Daraja field: ResultURL
282
+ */
283
+ resultUrl: string;
284
+ /**
285
+ * URL Safaricom calls when the request times out in the queue.
286
+ * Must be publicly accessible. HTTPS required in production.
287
+ * Daraja field: QueueTimeOutURL
288
+ */
289
+ queueTimeOutUrl: string;
290
+ /**
291
+ * Optional additional information for the transaction.
292
+ * Daraja field: Occassion (sic — preserved Daraja typo)
293
+ */
294
+ occasion?: string;
295
+ }
296
+ /**
297
+ * Synchronous acknowledgement returned immediately by Daraja.
298
+ *
299
+ * Daraja response shape:
300
+ * {
301
+ * "OriginatorConversationID": "5118-111210482-1",
302
+ * "ConversationID": "AG_20230420_2010759fd5662ef6d054",
303
+ * "ResponseCode": "0",
304
+ * "ResponseDescription": "Accept the service request successfully"
305
+ * }
306
+ */
307
+ interface B2BBuyGoodsResponse {
308
+ /** Unique request identifier assigned by Daraja upon successful submission */
309
+ OriginatorConversationID: string;
310
+ /** Unique request identifier assigned by M-Pesa */
311
+ ConversationID: string;
312
+ /** "0" indicates the request was accepted for processing */
313
+ ResponseCode: string;
314
+ /** Human-readable submission status description */
315
+ ResponseDescription: string;
316
+ }
317
+ //#endregion
318
+ //#region src/mpesa/b2b-pay-bill/types.d.ts
319
+ /**
320
+ * src/mpesa/b2b-pay-bill/types.ts
321
+ *
322
+ * Strictly aligned with Safaricom Daraja Business Pay Bill API documentation.
323
+ * Endpoint: POST /mpesa/b2b/v1/paymentrequest
324
+ * CommandID: "BusinessPayBill"
325
+ *
326
+ * Moves money from your MMF/Working account to a recipient's utility account.
327
+ * SenderIdentifierType and RecieverIdentifierType are always "4" per docs.
328
+ */
329
+ /**
330
+ * The only CommandID supported by the Business Pay Bill API.
331
+ * Docs: "For this API use Business PayBill only"
332
+ */
333
+ type B2BPayBillCommandID = 'BusinessPayBill';
334
+ /**
335
+ * Request payload for Business Pay Bill.
336
+ *
337
+ * Daraja payload shape:
338
+ * {
339
+ * "Initiator": "API Username",
340
+ * "SecurityCredential": "FKX1/KPzT8hFO...",
341
+ * "CommandID": "BusinessPayBill",
342
+ * "SenderIdentifierType": "4",
343
+ * "RecieverIdentifierType":"4",
344
+ * "Amount": "239",
345
+ * "PartyA": "123456",
346
+ * "PartyB": "000000",
347
+ * "AccountReference": "353353",
348
+ * "Requester": "254700000000",
349
+ * "Remarks": "OK",
350
+ * "QueueTimeOutURL": "https://...",
351
+ * "ResultURL": "https://...",
352
+ * "Occassion": ""
353
+ * }
354
+ */
355
+ interface B2BPayBillRequest {
356
+ /**
357
+ * Transaction type. Must be "BusinessPayBill".
358
+ * Daraja field: CommandID
359
+ */
360
+ commandId: B2BPayBillCommandID;
361
+ /**
362
+ * Transaction amount in KES. Must be a whole number ≥ 1.
363
+ * Daraja field: Amount (sent as string per API spec)
364
+ */
365
+ amount: number;
366
+ /**
367
+ * Your shortcode from which money will be deducted.
368
+ * SenderIdentifierType is always "4" (Organisation ShortCode) per docs.
369
+ * Daraja field: PartyA
370
+ */
371
+ partyA: string;
372
+ /**
373
+ * The shortcode to which money will be moved (Paybill number).
374
+ * RecieverIdentifierType is always "4" (Organisation ShortCode) per docs.
375
+ * Daraja field: PartyB
376
+ */
377
+ partyB: string;
378
+ /**
379
+ * The account number associated with the payment (up to 13 characters).
380
+ * Daraja field: AccountReference
381
+ */
382
+ accountReference: string;
383
+ /**
384
+ * Optional. The consumer's mobile number on whose behalf you are paying.
385
+ * Format: 254XXXXXXXXX
386
+ * Daraja field: Requester
387
+ */
388
+ requester?: string;
389
+ /**
390
+ * Any additional information for the transaction.
391
+ * Daraja field: Remarks
392
+ */
393
+ remarks?: string;
394
+ /**
395
+ * URL Safaricom calls with the final async result after processing.
396
+ * Must be publicly accessible. HTTPS required in production.
397
+ * Daraja field: ResultURL
398
+ */
399
+ resultUrl: string;
400
+ /**
401
+ * URL Safaricom calls when the request times out in the queue.
402
+ * Must be publicly accessible. HTTPS required in production.
403
+ * Daraja field: QueueTimeOutURL
404
+ */
405
+ queueTimeOutUrl: string;
406
+ /**
407
+ * Optional additional information for the transaction.
408
+ * Daraja field: Occassion (sic — preserved Daraja typo)
409
+ */
410
+ occasion?: string;
411
+ }
412
+ /**
413
+ * Synchronous acknowledgement returned immediately by Daraja.
414
+ *
415
+ * Daraja response shape:
416
+ * {
417
+ * "OriginatorConversationID": "5118-111210482-1",
418
+ * "ConversationID": "AG_20230420_2010759fd5662ef6d054",
419
+ * "ResponseCode": "0",
420
+ * "Response Description": "Accept the service request successfully"
421
+ * }
422
+ *
423
+ * Note: Daraja uses "Response Description" (with a space) in their docs.
424
+ * We map this to ResponseDescription for consistency.
425
+ */
426
+ interface B2BPayBillResponse {
427
+ /** Unique request identifier assigned by Daraja upon successful submission */
428
+ OriginatorConversationID: string;
429
+ /** Unique request identifier assigned by M-Pesa */
430
+ ConversationID: string;
431
+ /** "0" indicates the request was accepted for processing */
432
+ ResponseCode: string;
433
+ /** Human-readable submission status description */
434
+ ResponseDescription: string;
435
+ }
436
+ //#endregion
437
+ //#region src/mpesa/bill-manager/types.d.ts
438
+ /**
439
+ * Bill Manager types.
440
+ *
441
+ * Strictly aligned with Safaricom Daraja Bill Manager API documentation.
442
+ *
443
+ * APIs:
444
+ * POST /v1/billmanager-invoice/optin — Opt-in shortcode
445
+ * POST /v1/billmanager-invoice/change-optin-details — Update opt-in details
446
+ * POST /v1/billmanager-invoice/single-invoicing — Send a single invoice
447
+ * POST /v1/billmanager-invoice/bulk-invoicing — Send bulk invoices (up to 1000)
448
+ * POST /v1/billmanager-invoice/cancel-single-invoice — Cancel a single invoice
449
+ * POST /v1/billmanager-invoice/cancel-bulk-invoices — Cancel multiple invoices
450
+ * POST /v1/billmanager-invoice/reconciliation — Acknowledge a payment
451
+ *
452
+ * Ref: Bill Manager — Daraja Developer Portal
453
+ */
454
+ interface BillManagerOptInRequest {
455
+ /**
456
+ * Organisation shortcode (Paybill or Buy Goods — 5 to 6 digits).
457
+ * Daraja field: shortcode
458
+ */
459
+ shortcode: string;
460
+ /**
461
+ * Official contact email for the organisation.
462
+ * Appears in invoices and receipts.
463
+ * Daraja field: email
464
+ */
465
+ email: string;
466
+ /**
467
+ * Official contact phone number (e.g. 0710XXXXXX).
468
+ * Appears in invoices and receipts.
469
+ * Daraja field: officialContact
470
+ */
471
+ officialContact: string;
472
+ /**
473
+ * Enable or disable SMS payment reminders.
474
+ * "1" = Enable (reminders sent 7 days, 3 days, and on the due date)
475
+ * "0" = Disable
476
+ * Daraja field: sendReminders
477
+ */
478
+ sendReminders: '1' | '0';
479
+ /**
480
+ * Logo image to embed in invoices and receipts.
481
+ * Accepts JPEG / JPG.
482
+ * Daraja field: logo
483
+ */
484
+ logo?: string;
485
+ /**
486
+ * Callback URL where Bill Manager POSTs payment notifications.
487
+ * Daraja field: callbackurl (lowercase — mapped internally)
488
+ */
489
+ callbackUrl: string;
490
+ }
491
+ interface BillManagerOptInResponse {
492
+ /**
493
+ * App key assigned upon successful onboarding.
494
+ * Example: "AG_2376487236_126732989KJ"
495
+ */
496
+ app_key?: string;
497
+ /** Human-readable result message */
498
+ resmsg: string;
499
+ /** Numeric status code — "200" = success */
500
+ rescode: string;
501
+ }
502
+ /**
503
+ * Same fields as opt-in.
504
+ * Sent to /v1/billmanager-invoice/change-optin-details.
505
+ */
506
+ type BillManagerUpdateOptInRequest = BillManagerOptInRequest;
507
+ interface BillManagerUpdateOptInResponse {
508
+ resmsg: string;
509
+ rescode: string;
510
+ }
511
+ interface BillManagerInvoiceItem {
512
+ /** Name / description of the billable item */
513
+ itemName: string;
514
+ /** Amount for this item in KES (whole number ≥ 1) */
515
+ amount: number;
516
+ }
517
+ interface BillManagerSingleInvoiceRequest {
518
+ /**
519
+ * Unique invoice reference on your system.
520
+ * Used to reference the invoice from both Bill Manager and your system.
521
+ * Daraja field: externalReference
522
+ */
523
+ externalReference: string;
524
+ /**
525
+ * Full name of the billed recipient — appears in the invoice SMS.
526
+ * Daraja field: billedFullName
527
+ */
528
+ billedFullName: string;
529
+ /**
530
+ * Safaricom phone number to receive the invoice SMS.
531
+ * Formats: 07XXXXXXXX or 254XXXXXXXXX
532
+ * Daraja field: billedPhoneNumber
533
+ */
534
+ billedPhoneNumber: string;
535
+ /**
536
+ * Month and year of the billing period, e.g. "August 2021".
537
+ * Daraja field: billedPeriod
538
+ */
539
+ billedPeriod: string;
540
+ /**
541
+ * Descriptive invoice name — appears in the SMS sent to the customer.
542
+ * Daraja field: invoiceName
543
+ */
544
+ invoiceName: string;
545
+ /**
546
+ * Payment due date.
547
+ * Format: YYYY-MM-DD or YYYY-MM-DD HH:MM:SS
548
+ * Daraja field: dueDate
549
+ */
550
+ dueDate: string;
551
+ /**
552
+ * Account number that uniquely identifies the customer.
553
+ * Could be a customer name, property unit, student name, etc.
554
+ * Daraja field: accountReference
555
+ */
556
+ accountReference: string;
557
+ /**
558
+ * Total invoice amount in KES. Must be a whole number ≥ 1.
559
+ * Sent as a string per Daraja docs.
560
+ * Daraja field: amount
561
+ */
562
+ amount: number;
563
+ /**
564
+ * Additional billable line items shown on the invoice (optional).
565
+ * Daraja field: invoiceItems
566
+ */
567
+ invoiceItems?: BillManagerInvoiceItem[];
568
+ }
569
+ interface BillManagerSingleInvoiceResponse {
570
+ /** Descriptive status message, e.g. "Invoice sent successfully" */
571
+ Status_Message?: string;
572
+ resmsg: string;
573
+ /** Numeric status code — "200" = success */
574
+ rescode: string;
575
+ }
576
+ interface BillManagerBulkInvoiceRequest {
577
+ /**
578
+ * Array of invoices to send.
579
+ * Maximum 1000 invoices per request.
580
+ * Daraja receives these as a JSON array (unwrapped internally).
581
+ */
582
+ invoices: BillManagerSingleInvoiceRequest[];
583
+ }
584
+ interface BillManagerBulkInvoiceResponse {
585
+ Status_Message?: string;
586
+ resmsg: string;
587
+ rescode: string;
588
+ }
589
+ interface BillManagerCancelInvoiceRequest {
590
+ /**
591
+ * External reference of the invoice to cancel.
592
+ * Partially or fully paid invoices cannot be cancelled.
593
+ */
594
+ externalReference: string;
595
+ }
596
+ interface BillManagerCancelInvoiceResponse {
597
+ Status_Message?: string;
598
+ resmsg: string;
599
+ rescode: string;
600
+ errors?: unknown[];
601
+ }
602
+ interface BillManagerCancelBulkInvoiceRequest {
603
+ /**
604
+ * External references of the invoices to cancel.
605
+ * Partially or fully paid invoices cannot be cancelled.
606
+ */
607
+ externalReferences: string[];
608
+ }
609
+ interface BillManagerCancelBulkInvoiceResponse {
610
+ Status_Message?: string;
611
+ resmsg: string;
612
+ rescode: string;
613
+ errors?: unknown[];
614
+ }
615
+ /**
616
+ * Acknowledgment body sent to Daraja after your system has processed a payment.
617
+ *
618
+ * Endpoint: POST /v1/billmanager-invoice/reconciliation
619
+ *
620
+ * Per Daraja docs:
621
+ * ```json
622
+ * {
623
+ * "paymentDate": "2021-10-01",
624
+ * "paidAmount": "800",
625
+ * "accountReference": "Balboa95",
626
+ * "transactionId": "PJB53MYR1N",
627
+ * "phoneNumber": "0710XXXXXX",
628
+ * "fullName": "John Doe",
629
+ * "invoiceName": "School Fees",
630
+ * "externalReference": "955"
631
+ * }
632
+ * ```
633
+ */
634
+ interface BillManagerReconciliationRequest {
635
+ /** Date payment was received, e.g. "2021-10-01" */
636
+ paymentDate: string;
637
+ /** Amount paid */
638
+ paidAmount: string;
639
+ /** Account reference */
640
+ accountReference: string;
641
+ /** M-PESA receipt / transaction ID */
642
+ transactionId: string;
643
+ /** Customer phone number */
644
+ phoneNumber: string;
645
+ /** Customer full name */
646
+ fullName: string;
647
+ /** Invoice name */
648
+ invoiceName: string;
649
+ /** Your external invoice reference */
650
+ externalReference: string;
651
+ }
652
+ interface BillManagerReconciliationResponse {
653
+ resmsg: string;
654
+ rescode: string;
655
+ }
656
+ //#endregion
657
+ //#region src/mpesa/dynamic-qr/types.d.ts
658
+ /**
659
+ * src/mpesa/dynamic-qr/types.ts
660
+ *
661
+ * Strict TypeScript types for the Safaricom Daraja Dynamic QR API.
662
+ *
663
+ * API endpoint: POST /mpesa/qrcode/v1/generate
664
+ *
665
+ * Daraja reference:
666
+ * https://developer.safaricom.co.ke/APIs/DynamicQRCode
667
+ */
668
+ /**
669
+ * Valid transaction type codes for Dynamic QR generation.
670
+ *
671
+ * | Code | Description |
672
+ * |------|------------------------------------------|
673
+ * | BG | Pay Merchant – Buy Goods (till number) |
674
+ * | WA | Withdraw Cash at Agent Till |
675
+ * | PB | Paybill or Business number |
676
+ * | SM | Send Money (mobile number) |
677
+ * | SB | Send to Business (MSISDN-format CPI) |
678
+ */
679
+ type QRTransactionCode = 'BG' | 'WA' | 'PB' | 'SM' | 'SB';
680
+ /**
681
+ * Parameters for generating a Dynamic QR code.
682
+ *
683
+ * Maps 1-to-1 to the Daraja API body (camelCase → Daraja PascalCase
684
+ * conversion is handled inside `generateDynamicQR`).
685
+ */
686
+ interface DynamicQRRequest {
687
+ /**
688
+ * Name of the company / M-PESA merchant to embed in the QR.
689
+ * Daraja field: `MerchantName`
690
+ *
691
+ * @example "TEST SUPERMARKET"
692
+ */
693
+ merchantName: string;
694
+ /**
695
+ * Transaction reference shown to the customer on their phone.
696
+ * Daraja field: `RefNo`
697
+ *
698
+ * @example "Invoice Test"
699
+ * @example "INV-2024-001"
700
+ */
701
+ refNo: string;
702
+ /**
703
+ * Total transaction amount in KES (whole numbers only — fractions are
704
+ * rejected by Daraja). The value is rounded to the nearest integer
705
+ * before being sent.
706
+ * Daraja field: `Amount`
707
+ *
708
+ * @minimum 1
709
+ * @example 500
710
+ */
711
+ amount: number;
712
+ /**
713
+ * Transaction type code.
714
+ *
715
+ * - `"BG"` — Buy Goods (till number as CPI)
716
+ * - `"WA"` — Withdraw Cash at Agent Till
717
+ * - `"PB"` — Paybill / Business Number
718
+ * - `"SM"` — Send Money (customer MSISDN as CPI)
719
+ * - `"SB"` — Send to Business (MSISDN-format CPI)
720
+ *
721
+ * Daraja field: `TrxCode`
722
+ */
723
+ trxCode: QRTransactionCode;
724
+ /**
725
+ * Credit Party Identifier — the destination of funds.
726
+ *
727
+ * The required format depends on `trxCode`:
728
+ * - `BG` → till number
729
+ * - `WA` → agent till number
730
+ * - `PB` → paybill / business number
731
+ * - `SM` → customer MSISDN (e.g. `"254712345678"`)
732
+ * - `SB` → MSISDN-format business number
733
+ *
734
+ * Daraja field: `CPI`
735
+ *
736
+ * @example "373132" // BG
737
+ * @example "174379" // PB
738
+ * @example "254712345678" // SM
739
+ */
740
+ cpi: string;
741
+ /**
742
+ * Width (and height) of the generated QR code image in pixels.
743
+ * The image is always square.
744
+ *
745
+ * Daraja field: `Size` (sent as a string, e.g. `"300"`)
746
+ *
747
+ * @default 300
748
+ * @minimum 1
749
+ * @maximum 1000
750
+ * @example 300
751
+ */
752
+ size?: number;
753
+ }
754
+ /**
755
+ * Successful response from the Daraja Dynamic QR API.
756
+ */
757
+ interface DynamicQRResponse {
758
+ /**
759
+ * Unique transaction identifier assigned by Daraja.
760
+ * Daraja field: `ResponseCode`
761
+ *
762
+ * @example "AG_20191219_000043fdf61864fe9ff5"
763
+ */
764
+ ResponseCode: string;
765
+ /**
766
+ * Internal Daraja request ID for tracing.
767
+ * Daraja field: `RequestID`
768
+ *
769
+ * @example "16738-27456357-1"
770
+ */
771
+ RequestID: string;
772
+ /**
773
+ * Human-readable status message.
774
+ * Daraja field: `ResponseDescription`
775
+ *
776
+ * @example "QR Code Successfully Generated."
777
+ */
778
+ ResponseDescription: string;
779
+ /**
780
+ * Base64-encoded PNG of the QR code image.
781
+ *
782
+ * Render in a browser:
783
+ * ```html
784
+ * <img src="data:image/png;base64,{QRCode}" />
785
+ * ```
786
+ *
787
+ * Or write to disk:
788
+ * ```ts
789
+ * import { writeFileSync } from 'node:fs'
790
+ * writeFileSync('qr.png', Buffer.from(response.QRCode, 'base64'))
791
+ * ```
792
+ *
793
+ * Daraja field: `QRCode`
794
+ */
795
+ QRCode: string;
796
+ }
797
+ //#endregion
798
+ //#region src/mpesa/index.d.ts
799
+ declare class Mpesa {
800
+ private readonly config;
801
+ private readonly tokenManager;
802
+ private readonly baseUrl;
803
+ readonly idempotencyManager: IdempotencyManager;
804
+ constructor(config: MpesaConfig);
805
+ /** Idempotency options passed to all outbound Daraja HTTP calls. */
806
+ private darajaHttp;
807
+ private getToken;
808
+ private buildSecurityCredential;
809
+ private requireInitiator;
810
+ stkPushSafe(request: Omit<StkPushRequest, 'shortCode' | 'passKey'>): Promise<Result<Awaited<ReturnType<typeof this.stkPush>>>>;
811
+ accountBalanceSafe(request: AccountBalanceRequest): Promise<Result<AccountBalanceResponse>>;
812
+ stkPush(request: Omit<StkPushRequest, 'shortCode' | 'passKey'>): Promise<StkPushResponse>;
813
+ stkQuery(request: Omit<StkQueryRequest, 'shortCode' | 'passKey'>): Promise<StkQueryResponse>;
814
+ transactionStatus(request: TransactionStatusRequest): Promise<TransactionStatusResponse>;
815
+ accountBalance(request: AccountBalanceRequest): Promise<AccountBalanceResponse>;
816
+ reverseTransaction(request: ReversalRequest): Promise<ReversalResponse>;
817
+ generateDynamicQR(request: DynamicQRRequest): Promise<DynamicQRResponse>;
818
+ registerC2BUrls(request: C2BRegisterUrlRequest): Promise<C2BRegisterUrlResponse>;
819
+ simulateC2B(request: C2BSimulateRequest): Promise<C2BSimulateResponse>;
820
+ remitTax(request: TaxRemittanceRequest): Promise<TaxRemittanceResponse>;
821
+ b2bExpressCheckout(request: B2BExpressCheckoutRequest): Promise<B2BExpressCheckoutResponse>;
822
+ b2bBuyGoods(request: B2BBuyGoodsRequest): Promise<B2BBuyGoodsResponse>;
823
+ b2bPayBill(request: B2BPayBillRequest): Promise<B2BPayBillResponse>;
824
+ b2cPayment(request: B2CRequest): Promise<B2CResponse>;
825
+ b2cDisbursement(request: B2CDisbursementRequest): Promise<B2CDisbursementResponse>;
826
+ billManagerOptIn(request: BillManagerOptInRequest): Promise<BillManagerOptInResponse>;
827
+ updateOptIn(request: BillManagerUpdateOptInRequest): Promise<BillManagerUpdateOptInResponse>;
828
+ sendInvoice(request: BillManagerSingleInvoiceRequest): Promise<BillManagerSingleInvoiceResponse>;
829
+ sendBulkInvoices(request: BillManagerBulkInvoiceRequest): Promise<BillManagerBulkInvoiceResponse>;
830
+ cancelInvoice(request: BillManagerCancelInvoiceRequest): Promise<BillManagerCancelInvoiceResponse>;
831
+ cancelBulkInvoices(request: BillManagerCancelBulkInvoiceRequest): Promise<BillManagerCancelBulkInvoiceResponse>;
832
+ reconcilePayment(request: BillManagerReconciliationRequest): Promise<BillManagerReconciliationResponse>;
833
+ clearTokenCache(): void;
834
+ get environment(): Environment;
835
+ }
836
+ //#endregion
837
+ export { Mpesa as t };