pesafy 0.0.2 → 0.2.0

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.
package/dist/types.d.ts CHANGED
@@ -46,6 +46,138 @@ declare class IdempotencyManager {
46
46
  private pruneExpired;
47
47
  }
48
48
  //#endregion
49
+ //#region src/mpesa/stk-push/types.d.ts
50
+ /**
51
+ * src/mpesa/stk-push/types.ts
52
+ *
53
+ * Types, constants, and helpers for the M-PESA STK Push (M-PESA Express) API.
54
+ *
55
+ * Daraja docs:
56
+ * STK Push → POST /mpesa/stkpush/v1/processrequest
57
+ * STK Query → POST /mpesa/stkpushquery/v1/query
58
+ */
59
+ type TransactionType = 'CustomerPayBillOnline' | 'CustomerBuyGoodsOnline';
60
+ interface StkPushRequest {
61
+ /**
62
+ * Transaction amount in KES.
63
+ * Min: {@link STK_PUSH_LIMITS.MIN_AMOUNT} (KES 1)
64
+ * Max: {@link STK_PUSH_LIMITS.MAX_AMOUNT} (KES 250 000)
65
+ * Must round to a whole number ≥ 1.
66
+ * Daraja field: `Amount`
67
+ */
68
+ amount: number;
69
+ /**
70
+ * Phone number sending the money. Format: 2547XXXXXXXX.
71
+ * Must be a valid Safaricom M-PESA number.
72
+ * Daraja fields: `PartyA`, `PhoneNumber`
73
+ */
74
+ phoneNumber: string;
75
+ /**
76
+ * URL where Safaricom will POST the callback result.
77
+ * Must be publicly accessible (use ngrok/localtunnel for local dev).
78
+ * Daraja field: `CallBackURL`
79
+ */
80
+ callbackUrl: string;
81
+ /**
82
+ * Alpha-numeric reference shown to customer in the USSD prompt.
83
+ * Truncated to max 12 characters before sending.
84
+ * Daraja field: `AccountReference`
85
+ */
86
+ accountReference: string;
87
+ /**
88
+ * Additional description for the transaction.
89
+ * Truncated to max 13 characters before sending.
90
+ * Daraja field: `TransactionDesc`
91
+ */
92
+ transactionDesc: string;
93
+ /**
94
+ * Business shortcode — Paybill number or HO/Store number for Till.
95
+ * Daraja field: `BusinessShortCode`
96
+ */
97
+ shortCode: string;
98
+ /**
99
+ * Passkey used to generate the Password.
100
+ * Sandbox: from Daraja simulator test data.
101
+ * Production: emailed after Go Live.
102
+ */
103
+ passKey: string;
104
+ /**
105
+ * "CustomerPayBillOnline" (default) for Paybill.
106
+ * "CustomerBuyGoodsOnline" for Till Numbers.
107
+ * Daraja field: `TransactionType`
108
+ */
109
+ transactionType?: TransactionType;
110
+ /**
111
+ * Credit party receiving funds.
112
+ * - CustomerPayBillOnline → defaults to `shortCode`
113
+ * - CustomerBuyGoodsOnline → set to the Till Number
114
+ * Daraja field: `PartyB`
115
+ */
116
+ partyB?: string;
117
+ }
118
+ /**
119
+ * Synchronous acknowledgement returned immediately after STK Push submission.
120
+ * This is NOT the payment result — the result arrives via callback.
121
+ *
122
+ * Daraja endpoint: POST /mpesa/stkpush/v1/processrequest
123
+ */
124
+ interface StkPushResponse {
125
+ /** Global unique identifier for the submitted payment request */
126
+ MerchantRequestID: string;
127
+ /** Global unique identifier for the checkout transaction — use this for STK Query */
128
+ CheckoutRequestID: string;
129
+ /**
130
+ * "0" = request accepted successfully.
131
+ * Any other value = submission error.
132
+ */
133
+ ResponseCode: string;
134
+ /** Human-readable submission status */
135
+ ResponseDescription: string;
136
+ /** Message shown to customer on their device */
137
+ CustomerMessage: string;
138
+ }
139
+ /**
140
+ * Parameters for querying the status of a previously initiated STK Push.
141
+ *
142
+ * Daraja endpoint: POST /mpesa/stkpushquery/v1/query
143
+ */
144
+ interface StkQueryRequest {
145
+ /** `CheckoutRequestID` from the STK Push response */
146
+ checkoutRequestId: string;
147
+ shortCode: string;
148
+ passKey: string;
149
+ }
150
+ /**
151
+ * Response from the STK Query API.
152
+ *
153
+ * Note: `ResultCode` is documented as "Numeric" by Daraja.
154
+ * The Daraja JSON example shows it as a string (`"ResultCode": "0"`),
155
+ * but actual API responses return a number. Typed as `number` here.
156
+ * Use {@link STK_RESULT_CODES} constants for comparisons.
157
+ */
158
+ interface StkQueryResponse {
159
+ /** "0" = request accepted. Not the final payment status. */
160
+ ResponseCode: string;
161
+ /** Submission status message */
162
+ ResponseDescription: string;
163
+ /** Unique identifier for the merchant request */
164
+ MerchantRequestID: string;
165
+ /** Unique identifier for the checkout transaction */
166
+ CheckoutRequestID: string;
167
+ /**
168
+ * Payment processing status code.
169
+ * See {@link STK_RESULT_CODES} for all documented values:
170
+ * 0 → success
171
+ * 1 → insufficient balance
172
+ * 1032 → cancelled by user
173
+ * 1037 → phone unreachable
174
+ * 2001 → wrong PIN
175
+ */
176
+ ResultCode: number;
177
+ /** Human-readable description of the result */
178
+ ResultDesc: string;
179
+ }
180
+ //#endregion
49
181
  //#region src/mpesa/transaction-status/types.d.ts
50
182
  /**
51
183
  * Transaction Status Query types
@@ -200,6 +332,72 @@ interface MpesaConfig {
200
332
  };
201
333
  }
202
334
  //#endregion
335
+ //#region src/utils/errors/index.d.ts
336
+ /**
337
+ * Pesafy error types — single source of truth.
338
+ *
339
+ * All codes map to a specific failure category so callers can handle
340
+ * them without string-matching on the message.
341
+ */
342
+ 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"];
343
+ type ErrorCode = (typeof ERROR_CODES)[number];
344
+ interface PesafyErrorOptions {
345
+ code: ErrorCode;
346
+ message: string;
347
+ /** HTTP status code from Daraja (if applicable) */
348
+ statusCode?: number;
349
+ /** Raw Daraja response body (for debugging) */
350
+ response?: unknown;
351
+ /** Underlying caught error (network, crypto, etc.) */
352
+ cause?: unknown;
353
+ /** Daraja requestId from the error envelope */
354
+ requestId?: string;
355
+ /** Whether this error is retryable */
356
+ retryable?: boolean;
357
+ }
358
+ declare class PesafyError extends Error {
359
+ readonly code: ErrorCode;
360
+ readonly statusCode: number | undefined;
361
+ readonly response: unknown;
362
+ readonly requestId: string | undefined;
363
+ readonly cause: unknown;
364
+ readonly retryable: boolean;
365
+ constructor(options: PesafyErrorOptions);
366
+ /** Returns true if this is a validation error (user bug — do not retry) */
367
+ get isValidation(): boolean;
368
+ /** Returns true if this is an auth error */
369
+ get isAuth(): boolean;
370
+ toJSON(): {
371
+ name: string;
372
+ 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";
373
+ message: string;
374
+ statusCode: number | undefined;
375
+ requestId: string | undefined;
376
+ retryable: boolean;
377
+ };
378
+ }
379
+ //#endregion
380
+ //#region src/types/branded.d.ts
381
+ /**
382
+ * A discriminated union result — either Ok<T> or Err<E>.
383
+ * Prefer this over throwing in application-level code.
384
+ *
385
+ * @example
386
+ * const result = await mpesa.stkPushSafe({ ... });
387
+ * if (result.ok) {
388
+ * console.log(result.data.CheckoutRequestID);
389
+ * } else {
390
+ * console.error(result.error.code, result.error.message);
391
+ * }
392
+ */
393
+ type Result<T, E = PesafyError> = {
394
+ readonly ok: true;
395
+ readonly data: T;
396
+ } | {
397
+ readonly ok: false;
398
+ readonly error: E;
399
+ };
400
+ //#endregion
203
401
  //#region src/mpesa/account-balance/types.d.ts
204
402
  interface AccountBalanceRequest {
205
403
  /**
@@ -480,6 +678,242 @@ interface B2BExpressCheckoutCallbackFailed {
480
678
  */
481
679
  type B2BExpressCheckoutCallback = B2BExpressCheckoutCallbackSuccess | B2BExpressCheckoutCallbackCancelled | B2BExpressCheckoutCallbackFailed;
482
680
  //#endregion
681
+ //#region src/mpesa/b2b-buy-goods/types.d.ts
682
+ /**
683
+ * src/mpesa/b2b-buy-goods/types.ts
684
+ *
685
+ * Strictly aligned with Safaricom Daraja Business Buy Goods API documentation.
686
+ * Endpoint: POST /mpesa/b2b/v1/paymentrequest
687
+ * CommandID: "BusinessBuyGoods"
688
+ *
689
+ * Moves money from your MMF/Working account to the recipient's merchant account
690
+ * (till number, merchant store number, or Merchant HO).
691
+ * SenderIdentifierType and RecieverIdentifierType are always "4" per docs.
692
+ */
693
+ /**
694
+ * The only CommandID supported by the Business Buy Goods API.
695
+ * Docs: "For this API use BusinessBuyGoods only"
696
+ */
697
+ type B2BBuyGoodsCommandID = 'BusinessBuyGoods';
698
+ /**
699
+ * Request payload for Business Buy Goods.
700
+ *
701
+ * Daraja payload shape:
702
+ * {
703
+ * "Initiator": "API_Username",
704
+ * "SecurityCredential": "FKX1/KPzT8hFO...",
705
+ * "CommandID": "BusinessBuyGoods",
706
+ * "SenderIdentifierType": "4",
707
+ * "RecieverIdentifierType": "4",
708
+ * "Amount": "239",
709
+ * "PartyA": "123456",
710
+ * "PartyB": "000000",
711
+ * "AccountReference": "353353",
712
+ * "Requester": "254700000000",
713
+ * "Remarks": "OK",
714
+ * "QueueTimeOutURL": "https://...",
715
+ * "ResultURL": "https://...",
716
+ * "Occassion": ""
717
+ * }
718
+ */
719
+ interface B2BBuyGoodsRequest {
720
+ /**
721
+ * Transaction type. Must be "BusinessBuyGoods".
722
+ * Daraja field: CommandID
723
+ */
724
+ commandId: B2BBuyGoodsCommandID;
725
+ /**
726
+ * Transaction amount in KES. Must be a whole number ≥ 1.
727
+ * Daraja field: Amount (sent as string per API spec)
728
+ */
729
+ amount: number;
730
+ /**
731
+ * Your shortcode from which money will be deducted.
732
+ * SenderIdentifierType is always "4" (Organisation ShortCode) per docs.
733
+ * Daraja field: PartyA
734
+ */
735
+ partyA: string;
736
+ /**
737
+ * The till number / merchant store number / Merchant HO to which money is moved.
738
+ * RecieverIdentifierType is always "4" (Organisation ShortCode) per docs.
739
+ * Daraja field: PartyB
740
+ */
741
+ partyB: string;
742
+ /**
743
+ * The account number associated with the payment (up to 13 characters).
744
+ * Daraja field: AccountReference
745
+ */
746
+ accountReference: string;
747
+ /**
748
+ * Optional. The consumer's mobile number on whose behalf you are paying.
749
+ * Format: 254XXXXXXXXX
750
+ * Daraja field: Requester
751
+ */
752
+ requester?: string;
753
+ /**
754
+ * Any additional information for the transaction.
755
+ * Daraja field: Remarks
756
+ */
757
+ remarks?: string;
758
+ /**
759
+ * URL Safaricom calls with the final async result after processing.
760
+ * Must be publicly accessible. HTTPS required in production.
761
+ * Daraja field: ResultURL
762
+ */
763
+ resultUrl: string;
764
+ /**
765
+ * URL Safaricom calls when the request times out in the queue.
766
+ * Must be publicly accessible. HTTPS required in production.
767
+ * Daraja field: QueueTimeOutURL
768
+ */
769
+ queueTimeOutUrl: string;
770
+ /**
771
+ * Optional additional information for the transaction.
772
+ * Daraja field: Occassion (sic — preserved Daraja typo)
773
+ */
774
+ occasion?: string;
775
+ }
776
+ /**
777
+ * Synchronous acknowledgement returned immediately by Daraja.
778
+ *
779
+ * Daraja response shape:
780
+ * {
781
+ * "OriginatorConversationID": "5118-111210482-1",
782
+ * "ConversationID": "AG_20230420_2010759fd5662ef6d054",
783
+ * "ResponseCode": "0",
784
+ * "ResponseDescription": "Accept the service request successfully"
785
+ * }
786
+ */
787
+ interface B2BBuyGoodsResponse {
788
+ /** Unique request identifier assigned by Daraja upon successful submission */
789
+ OriginatorConversationID: string;
790
+ /** Unique request identifier assigned by M-Pesa */
791
+ ConversationID: string;
792
+ /** "0" indicates the request was accepted for processing */
793
+ ResponseCode: string;
794
+ /** Human-readable submission status description */
795
+ ResponseDescription: string;
796
+ }
797
+ //#endregion
798
+ //#region src/mpesa/b2b-pay-bill/types.d.ts
799
+ /**
800
+ * src/mpesa/b2b-pay-bill/types.ts
801
+ *
802
+ * Strictly aligned with Safaricom Daraja Business Pay Bill API documentation.
803
+ * Endpoint: POST /mpesa/b2b/v1/paymentrequest
804
+ * CommandID: "BusinessPayBill"
805
+ *
806
+ * Moves money from your MMF/Working account to a recipient's utility account.
807
+ * SenderIdentifierType and RecieverIdentifierType are always "4" per docs.
808
+ */
809
+ /**
810
+ * The only CommandID supported by the Business Pay Bill API.
811
+ * Docs: "For this API use Business PayBill only"
812
+ */
813
+ type B2BPayBillCommandID = 'BusinessPayBill';
814
+ /**
815
+ * Request payload for Business Pay Bill.
816
+ *
817
+ * Daraja payload shape:
818
+ * {
819
+ * "Initiator": "API Username",
820
+ * "SecurityCredential": "FKX1/KPzT8hFO...",
821
+ * "CommandID": "BusinessPayBill",
822
+ * "SenderIdentifierType": "4",
823
+ * "RecieverIdentifierType":"4",
824
+ * "Amount": "239",
825
+ * "PartyA": "123456",
826
+ * "PartyB": "000000",
827
+ * "AccountReference": "353353",
828
+ * "Requester": "254700000000",
829
+ * "Remarks": "OK",
830
+ * "QueueTimeOutURL": "https://...",
831
+ * "ResultURL": "https://...",
832
+ * "Occassion": ""
833
+ * }
834
+ */
835
+ interface B2BPayBillRequest {
836
+ /**
837
+ * Transaction type. Must be "BusinessPayBill".
838
+ * Daraja field: CommandID
839
+ */
840
+ commandId: B2BPayBillCommandID;
841
+ /**
842
+ * Transaction amount in KES. Must be a whole number ≥ 1.
843
+ * Daraja field: Amount (sent as string per API spec)
844
+ */
845
+ amount: number;
846
+ /**
847
+ * Your shortcode from which money will be deducted.
848
+ * SenderIdentifierType is always "4" (Organisation ShortCode) per docs.
849
+ * Daraja field: PartyA
850
+ */
851
+ partyA: string;
852
+ /**
853
+ * The shortcode to which money will be moved (Paybill number).
854
+ * RecieverIdentifierType is always "4" (Organisation ShortCode) per docs.
855
+ * Daraja field: PartyB
856
+ */
857
+ partyB: string;
858
+ /**
859
+ * The account number associated with the payment (up to 13 characters).
860
+ * Daraja field: AccountReference
861
+ */
862
+ accountReference: string;
863
+ /**
864
+ * Optional. The consumer's mobile number on whose behalf you are paying.
865
+ * Format: 254XXXXXXXXX
866
+ * Daraja field: Requester
867
+ */
868
+ requester?: string;
869
+ /**
870
+ * Any additional information for the transaction.
871
+ * Daraja field: Remarks
872
+ */
873
+ remarks?: string;
874
+ /**
875
+ * URL Safaricom calls with the final async result after processing.
876
+ * Must be publicly accessible. HTTPS required in production.
877
+ * Daraja field: ResultURL
878
+ */
879
+ resultUrl: string;
880
+ /**
881
+ * URL Safaricom calls when the request times out in the queue.
882
+ * Must be publicly accessible. HTTPS required in production.
883
+ * Daraja field: QueueTimeOutURL
884
+ */
885
+ queueTimeOutUrl: string;
886
+ /**
887
+ * Optional additional information for the transaction.
888
+ * Daraja field: Occassion (sic — preserved Daraja typo)
889
+ */
890
+ occasion?: string;
891
+ }
892
+ /**
893
+ * Synchronous acknowledgement returned immediately by Daraja.
894
+ *
895
+ * Daraja response shape:
896
+ * {
897
+ * "OriginatorConversationID": "5118-111210482-1",
898
+ * "ConversationID": "AG_20230420_2010759fd5662ef6d054",
899
+ * "ResponseCode": "0",
900
+ * "Response Description": "Accept the service request successfully"
901
+ * }
902
+ *
903
+ * Note: Daraja uses "Response Description" (with a space) in their docs.
904
+ * We map this to ResponseDescription for consistency.
905
+ */
906
+ interface B2BPayBillResponse {
907
+ /** Unique request identifier assigned by Daraja upon successful submission */
908
+ OriginatorConversationID: string;
909
+ /** Unique request identifier assigned by M-Pesa */
910
+ ConversationID: string;
911
+ /** "0" indicates the request was accepted for processing */
912
+ ResponseCode: string;
913
+ /** Human-readable submission status description */
914
+ ResponseDescription: string;
915
+ }
916
+ //#endregion
483
917
  //#region src/mpesa/b2c/types.d.ts
484
918
  /**
485
919
  * src/mpesa/b2c/types.ts
@@ -713,6 +1147,226 @@ interface B2CDisbursementResult {
713
1147
  };
714
1148
  }
715
1149
  //#endregion
1150
+ //#region src/mpesa/bill-manager/types.d.ts
1151
+ /**
1152
+ * Bill Manager types.
1153
+ *
1154
+ * Strictly aligned with Safaricom Daraja Bill Manager API documentation.
1155
+ *
1156
+ * APIs:
1157
+ * POST /v1/billmanager-invoice/optin — Opt-in shortcode
1158
+ * POST /v1/billmanager-invoice/change-optin-details — Update opt-in details
1159
+ * POST /v1/billmanager-invoice/single-invoicing — Send a single invoice
1160
+ * POST /v1/billmanager-invoice/bulk-invoicing — Send bulk invoices (up to 1000)
1161
+ * POST /v1/billmanager-invoice/cancel-single-invoice — Cancel a single invoice
1162
+ * POST /v1/billmanager-invoice/cancel-bulk-invoices — Cancel multiple invoices
1163
+ * POST /v1/billmanager-invoice/reconciliation — Acknowledge a payment
1164
+ *
1165
+ * Ref: Bill Manager — Daraja Developer Portal
1166
+ */
1167
+ interface BillManagerOptInRequest {
1168
+ /**
1169
+ * Organisation shortcode (Paybill or Buy Goods — 5 to 6 digits).
1170
+ * Daraja field: shortcode
1171
+ */
1172
+ shortcode: string;
1173
+ /**
1174
+ * Official contact email for the organisation.
1175
+ * Appears in invoices and receipts.
1176
+ * Daraja field: email
1177
+ */
1178
+ email: string;
1179
+ /**
1180
+ * Official contact phone number (e.g. 0710XXXXXX).
1181
+ * Appears in invoices and receipts.
1182
+ * Daraja field: officialContact
1183
+ */
1184
+ officialContact: string;
1185
+ /**
1186
+ * Enable or disable SMS payment reminders.
1187
+ * "1" = Enable (reminders sent 7 days, 3 days, and on the due date)
1188
+ * "0" = Disable
1189
+ * Daraja field: sendReminders
1190
+ */
1191
+ sendReminders: '1' | '0';
1192
+ /**
1193
+ * Logo image to embed in invoices and receipts.
1194
+ * Accepts JPEG / JPG.
1195
+ * Daraja field: logo
1196
+ */
1197
+ logo?: string;
1198
+ /**
1199
+ * Callback URL where Bill Manager POSTs payment notifications.
1200
+ * Daraja field: callbackurl (lowercase — mapped internally)
1201
+ */
1202
+ callbackUrl: string;
1203
+ }
1204
+ interface BillManagerOptInResponse {
1205
+ /**
1206
+ * App key assigned upon successful onboarding.
1207
+ * Example: "AG_2376487236_126732989KJ"
1208
+ */
1209
+ app_key?: string;
1210
+ /** Human-readable result message */
1211
+ resmsg: string;
1212
+ /** Numeric status code — "200" = success */
1213
+ rescode: string;
1214
+ }
1215
+ /**
1216
+ * Same fields as opt-in.
1217
+ * Sent to /v1/billmanager-invoice/change-optin-details.
1218
+ */
1219
+ type BillManagerUpdateOptInRequest = BillManagerOptInRequest;
1220
+ interface BillManagerUpdateOptInResponse {
1221
+ resmsg: string;
1222
+ rescode: string;
1223
+ }
1224
+ interface BillManagerInvoiceItem {
1225
+ /** Name / description of the billable item */
1226
+ itemName: string;
1227
+ /** Amount for this item in KES (whole number ≥ 1) */
1228
+ amount: number;
1229
+ }
1230
+ interface BillManagerSingleInvoiceRequest {
1231
+ /**
1232
+ * Unique invoice reference on your system.
1233
+ * Used to reference the invoice from both Bill Manager and your system.
1234
+ * Daraja field: externalReference
1235
+ */
1236
+ externalReference: string;
1237
+ /**
1238
+ * Full name of the billed recipient — appears in the invoice SMS.
1239
+ * Daraja field: billedFullName
1240
+ */
1241
+ billedFullName: string;
1242
+ /**
1243
+ * Safaricom phone number to receive the invoice SMS.
1244
+ * Formats: 07XXXXXXXX or 254XXXXXXXXX
1245
+ * Daraja field: billedPhoneNumber
1246
+ */
1247
+ billedPhoneNumber: string;
1248
+ /**
1249
+ * Month and year of the billing period, e.g. "August 2021".
1250
+ * Daraja field: billedPeriod
1251
+ */
1252
+ billedPeriod: string;
1253
+ /**
1254
+ * Descriptive invoice name — appears in the SMS sent to the customer.
1255
+ * Daraja field: invoiceName
1256
+ */
1257
+ invoiceName: string;
1258
+ /**
1259
+ * Payment due date.
1260
+ * Format: YYYY-MM-DD or YYYY-MM-DD HH:MM:SS
1261
+ * Daraja field: dueDate
1262
+ */
1263
+ dueDate: string;
1264
+ /**
1265
+ * Account number that uniquely identifies the customer.
1266
+ * Could be a customer name, property unit, student name, etc.
1267
+ * Daraja field: accountReference
1268
+ */
1269
+ accountReference: string;
1270
+ /**
1271
+ * Total invoice amount in KES. Must be a whole number ≥ 1.
1272
+ * Sent as a string per Daraja docs.
1273
+ * Daraja field: amount
1274
+ */
1275
+ amount: number;
1276
+ /**
1277
+ * Additional billable line items shown on the invoice (optional).
1278
+ * Daraja field: invoiceItems
1279
+ */
1280
+ invoiceItems?: BillManagerInvoiceItem[];
1281
+ }
1282
+ interface BillManagerSingleInvoiceResponse {
1283
+ /** Descriptive status message, e.g. "Invoice sent successfully" */
1284
+ Status_Message?: string;
1285
+ resmsg: string;
1286
+ /** Numeric status code — "200" = success */
1287
+ rescode: string;
1288
+ }
1289
+ interface BillManagerBulkInvoiceRequest {
1290
+ /**
1291
+ * Array of invoices to send.
1292
+ * Maximum 1000 invoices per request.
1293
+ * Daraja receives these as a JSON array (unwrapped internally).
1294
+ */
1295
+ invoices: BillManagerSingleInvoiceRequest[];
1296
+ }
1297
+ interface BillManagerBulkInvoiceResponse {
1298
+ Status_Message?: string;
1299
+ resmsg: string;
1300
+ rescode: string;
1301
+ }
1302
+ interface BillManagerCancelInvoiceRequest {
1303
+ /**
1304
+ * External reference of the invoice to cancel.
1305
+ * Partially or fully paid invoices cannot be cancelled.
1306
+ */
1307
+ externalReference: string;
1308
+ }
1309
+ interface BillManagerCancelInvoiceResponse {
1310
+ Status_Message?: string;
1311
+ resmsg: string;
1312
+ rescode: string;
1313
+ errors?: unknown[];
1314
+ }
1315
+ interface BillManagerCancelBulkInvoiceRequest {
1316
+ /**
1317
+ * External references of the invoices to cancel.
1318
+ * Partially or fully paid invoices cannot be cancelled.
1319
+ */
1320
+ externalReferences: string[];
1321
+ }
1322
+ interface BillManagerCancelBulkInvoiceResponse {
1323
+ Status_Message?: string;
1324
+ resmsg: string;
1325
+ rescode: string;
1326
+ errors?: unknown[];
1327
+ }
1328
+ /**
1329
+ * Acknowledgment body sent to Daraja after your system has processed a payment.
1330
+ *
1331
+ * Endpoint: POST /v1/billmanager-invoice/reconciliation
1332
+ *
1333
+ * Per Daraja docs:
1334
+ * ```json
1335
+ * {
1336
+ * "paymentDate": "2021-10-01",
1337
+ * "paidAmount": "800",
1338
+ * "accountReference": "Balboa95",
1339
+ * "transactionId": "PJB53MYR1N",
1340
+ * "phoneNumber": "0710XXXXXX",
1341
+ * "fullName": "John Doe",
1342
+ * "invoiceName": "School Fees",
1343
+ * "externalReference": "955"
1344
+ * }
1345
+ * ```
1346
+ */
1347
+ interface BillManagerReconciliationRequest {
1348
+ /** Date payment was received, e.g. "2021-10-01" */
1349
+ paymentDate: string;
1350
+ /** Amount paid */
1351
+ paidAmount: string;
1352
+ /** Account reference */
1353
+ accountReference: string;
1354
+ /** M-PESA receipt / transaction ID */
1355
+ transactionId: string;
1356
+ /** Customer phone number */
1357
+ phoneNumber: string;
1358
+ /** Customer full name */
1359
+ fullName: string;
1360
+ /** Invoice name */
1361
+ invoiceName: string;
1362
+ /** Your external invoice reference */
1363
+ externalReference: string;
1364
+ }
1365
+ interface BillManagerReconciliationResponse {
1366
+ resmsg: string;
1367
+ rescode: string;
1368
+ }
1369
+ //#endregion
716
1370
  //#region src/mpesa/c2b/types.d.ts
717
1371
  /**
718
1372
  * src/mpesa/c2b/types.ts
@@ -740,8 +1394,8 @@ type C2BResponseType = 'Completed' | 'Cancelled';
740
1394
  * {
741
1395
  * "ShortCode": "601426",
742
1396
  * "ResponseType": "Completed",
743
- * "ConfirmationURL": "https://yourdomain.com/confirm",
744
- * "ValidationURL": "https://yourdomain.com/validate"
1397
+ * "ConfirmationURL": "https://example.com/confirm",
1398
+ * "ValidationURL": "https://example.com/validate"
745
1399
  * }
746
1400
  */
747
1401
  interface C2BRegisterUrlRequest {
@@ -963,6 +1617,147 @@ interface C2BConfirmationPayload {
963
1617
  LastName: string;
964
1618
  }
965
1619
  //#endregion
1620
+ //#region src/mpesa/dynamic-qr/types.d.ts
1621
+ /**
1622
+ * src/mpesa/dynamic-qr/types.ts
1623
+ *
1624
+ * Strict TypeScript types for the Safaricom Daraja Dynamic QR API.
1625
+ *
1626
+ * API endpoint: POST /mpesa/qrcode/v1/generate
1627
+ *
1628
+ * Daraja reference:
1629
+ * https://developer.safaricom.co.ke/APIs/DynamicQRCode
1630
+ */
1631
+ /**
1632
+ * Valid transaction type codes for Dynamic QR generation.
1633
+ *
1634
+ * | Code | Description |
1635
+ * |------|------------------------------------------|
1636
+ * | BG | Pay Merchant – Buy Goods (till number) |
1637
+ * | WA | Withdraw Cash at Agent Till |
1638
+ * | PB | Paybill or Business number |
1639
+ * | SM | Send Money (mobile number) |
1640
+ * | SB | Send to Business (MSISDN-format CPI) |
1641
+ */
1642
+ type QRTransactionCode = 'BG' | 'WA' | 'PB' | 'SM' | 'SB';
1643
+ /**
1644
+ * Parameters for generating a Dynamic QR code.
1645
+ *
1646
+ * Maps 1-to-1 to the Daraja API body (camelCase → Daraja PascalCase
1647
+ * conversion is handled inside `generateDynamicQR`).
1648
+ */
1649
+ interface DynamicQRRequest {
1650
+ /**
1651
+ * Name of the company / M-PESA merchant to embed in the QR.
1652
+ * Daraja field: `MerchantName`
1653
+ *
1654
+ * @example "TEST SUPERMARKET"
1655
+ */
1656
+ merchantName: string;
1657
+ /**
1658
+ * Transaction reference shown to the customer on their phone.
1659
+ * Daraja field: `RefNo`
1660
+ *
1661
+ * @example "Invoice Test"
1662
+ * @example "INV-2024-001"
1663
+ */
1664
+ refNo: string;
1665
+ /**
1666
+ * Total transaction amount in KES (whole numbers only — fractions are
1667
+ * rejected by Daraja). The value is rounded to the nearest integer
1668
+ * before being sent.
1669
+ * Daraja field: `Amount`
1670
+ *
1671
+ * @minimum 1
1672
+ * @example 500
1673
+ */
1674
+ amount: number;
1675
+ /**
1676
+ * Transaction type code.
1677
+ *
1678
+ * - `"BG"` — Buy Goods (till number as CPI)
1679
+ * - `"WA"` — Withdraw Cash at Agent Till
1680
+ * - `"PB"` — Paybill / Business Number
1681
+ * - `"SM"` — Send Money (customer MSISDN as CPI)
1682
+ * - `"SB"` — Send to Business (MSISDN-format CPI)
1683
+ *
1684
+ * Daraja field: `TrxCode`
1685
+ */
1686
+ trxCode: QRTransactionCode;
1687
+ /**
1688
+ * Credit Party Identifier — the destination of funds.
1689
+ *
1690
+ * The required format depends on `trxCode`:
1691
+ * - `BG` → till number
1692
+ * - `WA` → agent till number
1693
+ * - `PB` → paybill / business number
1694
+ * - `SM` → customer MSISDN (e.g. `"254712345678"`)
1695
+ * - `SB` → MSISDN-format business number
1696
+ *
1697
+ * Daraja field: `CPI`
1698
+ *
1699
+ * @example "373132" // BG
1700
+ * @example "174379" // PB
1701
+ * @example "254712345678" // SM
1702
+ */
1703
+ cpi: string;
1704
+ /**
1705
+ * Width (and height) of the generated QR code image in pixels.
1706
+ * The image is always square.
1707
+ *
1708
+ * Daraja field: `Size` (sent as a string, e.g. `"300"`)
1709
+ *
1710
+ * @default 300
1711
+ * @minimum 1
1712
+ * @maximum 1000
1713
+ * @example 300
1714
+ */
1715
+ size?: number;
1716
+ }
1717
+ /**
1718
+ * Successful response from the Daraja Dynamic QR API.
1719
+ */
1720
+ interface DynamicQRResponse {
1721
+ /**
1722
+ * Unique transaction identifier assigned by Daraja.
1723
+ * Daraja field: `ResponseCode`
1724
+ *
1725
+ * @example "AG_20191219_000043fdf61864fe9ff5"
1726
+ */
1727
+ ResponseCode: string;
1728
+ /**
1729
+ * Internal Daraja request ID for tracing.
1730
+ * Daraja field: `RequestID`
1731
+ *
1732
+ * @example "16738-27456357-1"
1733
+ */
1734
+ RequestID: string;
1735
+ /**
1736
+ * Human-readable status message.
1737
+ * Daraja field: `ResponseDescription`
1738
+ *
1739
+ * @example "QR Code Successfully Generated."
1740
+ */
1741
+ ResponseDescription: string;
1742
+ /**
1743
+ * Base64-encoded PNG of the QR code image.
1744
+ *
1745
+ * Render in a browser:
1746
+ * ```html
1747
+ * <img src="data:image/png;base64,{QRCode}" />
1748
+ * ```
1749
+ *
1750
+ * Or write to disk:
1751
+ * ```ts
1752
+ * import { writeFileSync } from 'node:fs'
1753
+ * writeFileSync('qr.png', Buffer.from(response.QRCode, 'base64'))
1754
+ * ```
1755
+ *
1756
+ * Daraja field: `QRCode`
1757
+ */
1758
+ QRCode: string;
1759
+ }
1760
+ //#endregion
966
1761
  //#region src/mpesa/reversal/types.d.ts
967
1762
  /**
968
1763
  * Keys present in the ResultParameters.ResultParameter array of a successful
@@ -982,8 +1777,8 @@ type ReversalResultParameterKey = 'DebitAccountBalance' | 'Amount' | 'TransCompl
982
1777
  * "Amount": "200",
983
1778
  * "ReceiverParty": "603021",
984
1779
  * "RecieverIdentifierType":"11",
985
- * "ResultURL": "https://mydomain.com/reversal/result",
986
- * "QueueTimeOutURL": "https://mydomain.com/reversal/queue",
1780
+ * "ResultURL": "https://example.org/reversal/result",
1781
+ * "QueueTimeOutURL": "https://example.org/reversal/queue",
987
1782
  * "Remarks": "Payment reversal"
988
1783
  * }
989
1784
  * ```
@@ -1256,4 +2051,128 @@ interface TaxRemittanceResult {
1256
2051
  };
1257
2052
  }
1258
2053
  //#endregion
1259
- export { TransactionStatusResult as A, AccountBalanceRequest as C, MpesaConfig as D, Environment as E, TransactionStatusRequest as O, B2BExpressCheckoutResponse as S, AccountBalanceResult as T, B2CRequest as _, ReversalResponse as a, B2BExpressCheckoutCallback as b, C2BRegisterUrlRequest as c, C2BSimulateResponse as d, C2BValidationPayload as f, B2CDisbursementResult as g, B2CDisbursementResponse as h, ReversalRequest as i, IdempotencyManager as j, TransactionStatusResponse as k, C2BRegisterUrlResponse as l, B2CDisbursementRequest as m, TaxRemittanceResponse as n, ReversalResult as o, C2BValidationResponse as p, TaxRemittanceResult as r, C2BConfirmationPayload as s, TaxRemittanceRequest as t, C2BSimulateRequest as u, B2CResponse as v, AccountBalanceResponse as w, B2BExpressCheckoutRequest as x, B2CResult as y };
2054
+ //#region src/mpesa/index.d.ts
2055
+ declare class Mpesa {
2056
+ private readonly config;
2057
+ private readonly tokenManager;
2058
+ private readonly baseUrl;
2059
+ readonly idempotencyManager: IdempotencyManager;
2060
+ constructor(config: MpesaConfig);
2061
+ /** Idempotency options passed to all outbound Daraja HTTP calls. */
2062
+ private darajaHttp;
2063
+ private getToken;
2064
+ private buildSecurityCredential;
2065
+ private requireInitiator;
2066
+ stkPushSafe(request: Omit<StkPushRequest, 'shortCode' | 'passKey'>): Promise<Result<Awaited<ReturnType<typeof this.stkPush>>>>;
2067
+ accountBalanceSafe(request: AccountBalanceRequest): Promise<Result<AccountBalanceResponse>>;
2068
+ stkPush(request: Omit<StkPushRequest, 'shortCode' | 'passKey'>): Promise<StkPushResponse>;
2069
+ stkQuery(request: Omit<StkQueryRequest, 'shortCode' | 'passKey'>): Promise<StkQueryResponse>;
2070
+ transactionStatus(request: TransactionStatusRequest): Promise<TransactionStatusResponse>;
2071
+ accountBalance(request: AccountBalanceRequest): Promise<AccountBalanceResponse>;
2072
+ reverseTransaction(request: ReversalRequest): Promise<ReversalResponse>;
2073
+ generateDynamicQR(request: DynamicQRRequest): Promise<DynamicQRResponse>;
2074
+ registerC2BUrls(request: C2BRegisterUrlRequest): Promise<C2BRegisterUrlResponse>;
2075
+ simulateC2B(request: C2BSimulateRequest): Promise<C2BSimulateResponse>;
2076
+ remitTax(request: TaxRemittanceRequest): Promise<TaxRemittanceResponse>;
2077
+ b2bExpressCheckout(request: B2BExpressCheckoutRequest): Promise<B2BExpressCheckoutResponse>;
2078
+ b2bBuyGoods(request: B2BBuyGoodsRequest): Promise<B2BBuyGoodsResponse>;
2079
+ b2bPayBill(request: B2BPayBillRequest): Promise<B2BPayBillResponse>;
2080
+ b2cPayment(request: B2CRequest): Promise<B2CResponse>;
2081
+ b2cDisbursement(request: B2CDisbursementRequest): Promise<B2CDisbursementResponse>;
2082
+ billManagerOptIn(request: BillManagerOptInRequest): Promise<BillManagerOptInResponse>;
2083
+ updateOptIn(request: BillManagerUpdateOptInRequest): Promise<BillManagerUpdateOptInResponse>;
2084
+ sendInvoice(request: BillManagerSingleInvoiceRequest): Promise<BillManagerSingleInvoiceResponse>;
2085
+ sendBulkInvoices(request: BillManagerBulkInvoiceRequest): Promise<BillManagerBulkInvoiceResponse>;
2086
+ cancelInvoice(request: BillManagerCancelInvoiceRequest): Promise<BillManagerCancelInvoiceResponse>;
2087
+ cancelBulkInvoices(request: BillManagerCancelBulkInvoiceRequest): Promise<BillManagerCancelBulkInvoiceResponse>;
2088
+ reconcilePayment(request: BillManagerReconciliationRequest): Promise<BillManagerReconciliationResponse>;
2089
+ clearTokenCache(): void;
2090
+ get environment(): Environment;
2091
+ }
2092
+ //#endregion
2093
+ //#region src/adapters/webhook-guard.d.ts
2094
+ /** Optional webhook security settings shared by framework adapters. */
2095
+ interface AdapterWebhookSecurityConfig {
2096
+ /** Skip Safaricom IP allowlist (local dev only). */
2097
+ skipIPCheck?: boolean;
2098
+ /** Shared secret for opt-in HMAC verification. */
2099
+ webhookSecret?: string;
2100
+ /** Reject when HMAC is required but missing/invalid. */
2101
+ requireHMAC?: boolean;
2102
+ /** Header carrying the HMAC signature (default: x-safaricom-signature). */
2103
+ signatureHeader?: string;
2104
+ }
2105
+ //#endregion
2106
+ //#region src/adapters/shared/types.d.ts
2107
+ type Awaitable<T> = T | Promise<T>;
2108
+ interface StkSuccessPayload {
2109
+ receiptNumber: string | null;
2110
+ amount: number | null;
2111
+ phone: string | null;
2112
+ checkoutRequestId: string;
2113
+ merchantRequestId: string;
2114
+ }
2115
+ interface StkFailurePayload {
2116
+ resultCode: number;
2117
+ resultDesc: string;
2118
+ checkoutRequestId: string;
2119
+ merchantRequestId: string;
2120
+ }
2121
+ interface MpesaAdapterConfig extends MpesaConfig, AdapterWebhookSecurityConfig {
2122
+ /** STK Push callback URL (required) */
2123
+ callbackUrl: string;
2124
+ /** Default ResultURL for async APIs (balance, reversal, tx-status, b2c, tax) */
2125
+ resultUrl?: string;
2126
+ /** Default QueueTimeOutURL */
2127
+ queueTimeoutUrl?: string;
2128
+ /** Prefix for all routes — default "" */
2129
+ routePrefix?: string;
2130
+ balance?: {
2131
+ resultUrl?: string;
2132
+ queueTimeoutUrl?: string;
2133
+ shortCode?: string;
2134
+ };
2135
+ reversal?: {
2136
+ resultUrl?: string;
2137
+ queueTimeoutUrl?: string;
2138
+ };
2139
+ txStatus?: {
2140
+ resultUrl?: string;
2141
+ queueTimeoutUrl?: string;
2142
+ };
2143
+ tax?: {
2144
+ resultUrl?: string;
2145
+ queueTimeoutUrl?: string;
2146
+ partyA?: string;
2147
+ };
2148
+ b2c?: {
2149
+ resultUrl?: string;
2150
+ queueTimeoutUrl?: string;
2151
+ partyA?: string;
2152
+ };
2153
+ c2b?: {
2154
+ shortCode?: string;
2155
+ confirmationUrl?: string;
2156
+ validationUrl?: string;
2157
+ responseType?: 'Completed' | 'Cancelled';
2158
+ apiVersion?: 'v1' | 'v2';
2159
+ };
2160
+ b2b?: {
2161
+ receiverShortCode?: string;
2162
+ callbackUrl?: string;
2163
+ };
2164
+ onStkSuccess?: (data: StkSuccessPayload) => Awaitable<void>;
2165
+ onStkFailure?: (data: StkFailurePayload) => Awaitable<void>;
2166
+ onC2BValidation?: (payload: C2BValidationPayload) => Awaitable<C2BValidationResponse>;
2167
+ onC2BConfirmation?: (payload: C2BConfirmationPayload) => Awaitable<void>;
2168
+ onAccountBalanceResult?: (result: AccountBalanceResult) => Awaitable<void>;
2169
+ onReversalResult?: (result: ReversalResult) => Awaitable<void>;
2170
+ onTxStatusResult?: (result: TransactionStatusResult) => Awaitable<void>;
2171
+ onTaxResult?: (result: TaxRemittanceResult) => Awaitable<void>;
2172
+ onB2BCheckoutCallback?: (callback: B2BExpressCheckoutCallback) => Awaitable<void>;
2173
+ onB2CResult?: (result: B2CResult) => Awaitable<void>;
2174
+ onB2CDisbursementResult?: (result: B2CDisbursementResult) => Awaitable<void>;
2175
+ }
2176
+ //#endregion
2177
+ export { Mpesa as i, StkFailurePayload as n, StkSuccessPayload as r, MpesaAdapterConfig as t };
2178
+ //# sourceMappingURL=types.d.ts.map