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.
- package/CHANGELOG.md +126 -0
- package/LICENSE +21 -0
- package/README.md +1519 -0
- package/dist/adapters/express.d.ts +106 -0
- package/dist/adapters/express.js +1 -0
- package/dist/adapters/fastify.d.ts +82 -0
- package/dist/adapters/fastify.js +1 -0
- package/dist/adapters/hono.d.ts +106 -0
- package/dist/adapters/hono.js +1 -0
- package/dist/adapters/nextjs.d.ts +183 -0
- package/dist/adapters/nextjs.js +1 -0
- package/dist/chunk.js +1 -0
- package/dist/cli.mjs +641 -0
- package/dist/encryption.mjs +22 -0
- package/dist/errors.mjs +41 -0
- package/dist/index.d.ts +837 -0
- package/dist/index.js +1 -0
- package/dist/phone.mjs +23 -0
- package/dist/react/index.d.ts +1 -0
- package/dist/react/index.js +0 -0
- package/dist/types.d.ts +1259 -0
- package/dist/utils.mjs +32 -0
- package/dist/webhook-guard.js +1 -0
- package/package.json +213 -0
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,1259 @@
|
|
|
1
|
+
//#region src/core/idempotency/store.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* In-memory idempotency store (per-process).
|
|
4
|
+
* For multi-instance deployments, supply a custom IdempotencyStore (e.g. Redis).
|
|
5
|
+
*/
|
|
6
|
+
interface IdempotencyEntry {
|
|
7
|
+
key: string;
|
|
8
|
+
createdAt: number;
|
|
9
|
+
completedAt?: number;
|
|
10
|
+
}
|
|
11
|
+
interface IdempotencyStore {
|
|
12
|
+
get(key: string): IdempotencyEntry | undefined;
|
|
13
|
+
set(key: string, entry: IdempotencyEntry): void;
|
|
14
|
+
delete(key: string): void;
|
|
15
|
+
}
|
|
16
|
+
//#endregion
|
|
17
|
+
//#region src/core/idempotency/manager.d.ts
|
|
18
|
+
interface IdempotencyConfig {
|
|
19
|
+
/** Default true for mutating POSTs */
|
|
20
|
+
enabled?: boolean;
|
|
21
|
+
/** HTTP header name. Default: Idempotency-Key */
|
|
22
|
+
headerName?: string;
|
|
23
|
+
/** Pluggable store; default in-memory */
|
|
24
|
+
store?: IdempotencyStore;
|
|
25
|
+
/** Dedup window in ms. Default: 24h */
|
|
26
|
+
ttlMs?: number;
|
|
27
|
+
/** Custom key generator */
|
|
28
|
+
generateKey?: () => string;
|
|
29
|
+
}
|
|
30
|
+
declare class IdempotencyManager {
|
|
31
|
+
readonly enabled: boolean;
|
|
32
|
+
readonly headerName: string;
|
|
33
|
+
readonly ttlMs: number;
|
|
34
|
+
private readonly store;
|
|
35
|
+
private readonly generateKey;
|
|
36
|
+
constructor(config?: IdempotencyConfig);
|
|
37
|
+
/**
|
|
38
|
+
* Reserve an idempotency key before the HTTP call.
|
|
39
|
+
* @throws PesafyError with IDEMPOTENCY_ERROR if duplicate in-flight/completed within TTL.
|
|
40
|
+
*/
|
|
41
|
+
reserve(key?: string): string;
|
|
42
|
+
/** Mark key as successfully completed. */
|
|
43
|
+
complete(key: string): void;
|
|
44
|
+
/** Release reservation on failure so callers can retry with same key. */
|
|
45
|
+
release(key: string): void;
|
|
46
|
+
private pruneExpired;
|
|
47
|
+
}
|
|
48
|
+
//#endregion
|
|
49
|
+
//#region src/mpesa/transaction-status/types.d.ts
|
|
50
|
+
/**
|
|
51
|
+
* Transaction Status Query types
|
|
52
|
+
*
|
|
53
|
+
* API: POST /mpesa/transactionstatus/v1/query
|
|
54
|
+
*
|
|
55
|
+
* Daraja request body (from official documentation):
|
|
56
|
+
* {
|
|
57
|
+
* "Initiator": "",
|
|
58
|
+
* "SecurityCredential": "",
|
|
59
|
+
* "CommandID": "TransactionStatusQuery",
|
|
60
|
+
* "TransactionID": "",
|
|
61
|
+
* "OriginalConversationID": "",
|
|
62
|
+
* "PartyA": "",
|
|
63
|
+
* "IdentifierType": "",
|
|
64
|
+
* "ResultURL": "",
|
|
65
|
+
* "QueueTimeOutURL": "",
|
|
66
|
+
* "Remarks": "",
|
|
67
|
+
* "Occasion": ""
|
|
68
|
+
* }
|
|
69
|
+
*
|
|
70
|
+
* NOTE: This is an ASYNCHRONOUS API.
|
|
71
|
+
* The synchronous response only confirms Safaricom received the request.
|
|
72
|
+
* The actual transaction details arrive later via POST to your ResultURL.
|
|
73
|
+
*
|
|
74
|
+
* Reconciliation: Either transactionId OR originalConversationId is required.
|
|
75
|
+
*/
|
|
76
|
+
interface TransactionStatusRequest {
|
|
77
|
+
/**
|
|
78
|
+
* M-Pesa transaction ID to look up (M-Pesa Receipt Number).
|
|
79
|
+
* Either transactionId OR originalConversationId is required.
|
|
80
|
+
* Daraja field: TransactionID
|
|
81
|
+
* Example: "NEF61H8J60"
|
|
82
|
+
*/
|
|
83
|
+
transactionId?: string;
|
|
84
|
+
/**
|
|
85
|
+
* The Originator Conversation ID of the transaction whose status is being
|
|
86
|
+
* checked. Either transactionId OR originalConversationId is required.
|
|
87
|
+
* Use this when you have a ConversationID from the original API response
|
|
88
|
+
* but no M-Pesa receipt number.
|
|
89
|
+
* Daraja field: OriginalConversationID
|
|
90
|
+
* Example: "7071-4170-a0e5-8345632bad4421"
|
|
91
|
+
*/
|
|
92
|
+
originalConversationId?: string;
|
|
93
|
+
/**
|
|
94
|
+
* Organization/MSISDN receiving the transaction.
|
|
95
|
+
* Usually your business shortcode.
|
|
96
|
+
* Daraja field: PartyA
|
|
97
|
+
*/
|
|
98
|
+
partyA: string;
|
|
99
|
+
/**
|
|
100
|
+
* Type of the partyA identifier.
|
|
101
|
+
* "1" = MSISDN
|
|
102
|
+
* "2" = Till Number (Buy Goods)
|
|
103
|
+
* "4" = Organisation ShortCode (Paybill / B2C) ← most common
|
|
104
|
+
* Daraja field: IdentifierType
|
|
105
|
+
*/
|
|
106
|
+
identifierType: '1' | '2' | '4';
|
|
107
|
+
/**
|
|
108
|
+
* URL where Safaricom POSTs the final result.
|
|
109
|
+
* Must be publicly accessible.
|
|
110
|
+
* Daraja field: ResultURL
|
|
111
|
+
*/
|
|
112
|
+
resultUrl: string;
|
|
113
|
+
/**
|
|
114
|
+
* URL Safaricom calls when the request times out in the queue.
|
|
115
|
+
* Must be publicly accessible.
|
|
116
|
+
* Daraja field: QueueTimeOutURL
|
|
117
|
+
*/
|
|
118
|
+
queueTimeOutUrl: string;
|
|
119
|
+
/**
|
|
120
|
+
* CommandID — always "TransactionStatusQuery".
|
|
121
|
+
* Defaults to "TransactionStatusQuery" if omitted.
|
|
122
|
+
*/
|
|
123
|
+
commandId?: 'TransactionStatusQuery';
|
|
124
|
+
/** Optional remarks (up to 100 characters) */
|
|
125
|
+
remarks?: string;
|
|
126
|
+
/** Optional occasion / reference (up to 100 characters) */
|
|
127
|
+
occasion?: string;
|
|
128
|
+
}
|
|
129
|
+
interface TransactionStatusResponse {
|
|
130
|
+
/** Unique request ID for tracking */
|
|
131
|
+
OriginatorConversationID: string;
|
|
132
|
+
/** Unique request ID returned by M-PESA */
|
|
133
|
+
ConversationID: string;
|
|
134
|
+
/** "0" = request accepted */
|
|
135
|
+
ResponseCode: string;
|
|
136
|
+
ResponseDescription: string;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Documented result parameter keys for the Transaction Status callback.
|
|
140
|
+
* @see Daraja Transaction Status result documentation
|
|
141
|
+
*/
|
|
142
|
+
type TransactionStatusResultParameterKey = 'DebitPartyName' | 'TransactionStatus' | 'Amount' | 'ReceiptNo' | 'DebitAccountBalance' | 'TransactionDate' | 'CreditPartyName';
|
|
143
|
+
interface TransactionStatusResultParameter {
|
|
144
|
+
Key: TransactionStatusResultParameterKey | string;
|
|
145
|
+
Value: string | number;
|
|
146
|
+
}
|
|
147
|
+
interface TransactionStatusResult {
|
|
148
|
+
Result: {
|
|
149
|
+
/** 0 = completed, 1 = waiting for further messages */ResultType: number | string; /** 0 = success */
|
|
150
|
+
ResultCode: number | string; /** Human-readable description of the result */
|
|
151
|
+
ResultDesc: string;
|
|
152
|
+
OriginatorConversationID: string;
|
|
153
|
+
ConversationID: string;
|
|
154
|
+
TransactionID: string;
|
|
155
|
+
ResultParameters?: {
|
|
156
|
+
ResultParameter: TransactionStatusResultParameter | TransactionStatusResultParameter[];
|
|
157
|
+
};
|
|
158
|
+
ReferenceData?: {
|
|
159
|
+
ReferenceItem: {
|
|
160
|
+
Key: string;
|
|
161
|
+
Value?: string;
|
|
162
|
+
} | Array<{
|
|
163
|
+
Key: string;
|
|
164
|
+
Value?: string;
|
|
165
|
+
}>;
|
|
166
|
+
};
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
//#endregion
|
|
170
|
+
//#region src/mpesa/types.d.ts
|
|
171
|
+
type Environment = 'sandbox' | 'production';
|
|
172
|
+
interface MpesaConfig {
|
|
173
|
+
consumerKey: string;
|
|
174
|
+
consumerSecret: string;
|
|
175
|
+
environment: Environment;
|
|
176
|
+
lipaNaMpesaShortCode?: string;
|
|
177
|
+
lipaNaMpesaPassKey?: string;
|
|
178
|
+
initiatorName?: string;
|
|
179
|
+
initiatorPassword?: string;
|
|
180
|
+
certificatePath?: string;
|
|
181
|
+
certificatePem?: string;
|
|
182
|
+
/**
|
|
183
|
+
* Pre-computed base64 SecurityCredential — skips RSA encryption.
|
|
184
|
+
* Use when you encrypt at startup outside the library.
|
|
185
|
+
*/
|
|
186
|
+
securityCredential?: string;
|
|
187
|
+
/** Override default retry count (4) for all API calls */
|
|
188
|
+
retries?: number;
|
|
189
|
+
/** Override default base retry delay in ms (2000) */
|
|
190
|
+
retryDelay?: number;
|
|
191
|
+
/** Override default per-request timeout in ms (30000) */
|
|
192
|
+
timeout?: number;
|
|
193
|
+
/** Automatic Idempotency-Key headers and duplicate detection */
|
|
194
|
+
idempotency?: IdempotencyConfig;
|
|
195
|
+
webhooks?: {
|
|
196
|
+
allowedIPs?: readonly string[]; /** HMAC secret when Safaricom ships signature support */
|
|
197
|
+
secret?: string; /** Signature header name (placeholder until official docs) */
|
|
198
|
+
signatureHeader?: string; /** Fail closed if HMAC required but missing. Default false */
|
|
199
|
+
requireHMAC?: boolean;
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
//#endregion
|
|
203
|
+
//#region src/mpesa/account-balance/types.d.ts
|
|
204
|
+
interface AccountBalanceRequest {
|
|
205
|
+
/**
|
|
206
|
+
* Your business shortcode from which balance is queried.
|
|
207
|
+
* Daraja field: PartyA (Numeric)
|
|
208
|
+
* Example: "600000"
|
|
209
|
+
*/
|
|
210
|
+
partyA: string;
|
|
211
|
+
/**
|
|
212
|
+
* Type of the PartyA identifier.
|
|
213
|
+
* "1" = MSISDN
|
|
214
|
+
* "2" = Till Number
|
|
215
|
+
* "4" = Organisation ShortCode (most common — Paybill/B2C/Buy Goods)
|
|
216
|
+
* Daraja field: IdentifierType (Numeric)
|
|
217
|
+
* Sample: 4
|
|
218
|
+
*/
|
|
219
|
+
identifierType: '1' | '2' | '4';
|
|
220
|
+
/**
|
|
221
|
+
* URL where Safaricom POSTs the balance result (async callback).
|
|
222
|
+
* Must be publicly accessible. HTTPS required in production.
|
|
223
|
+
* Daraja field: ResultURL (URL)
|
|
224
|
+
* Sample: https://ip:port/path or domain:port/path
|
|
225
|
+
*/
|
|
226
|
+
resultUrl: string;
|
|
227
|
+
/**
|
|
228
|
+
* URL Safaricom calls when the request times out.
|
|
229
|
+
* Daraja field: QueueTimeOutURL (URL)
|
|
230
|
+
* Sample: https://ip:port/path or domain:port/path
|
|
231
|
+
*/
|
|
232
|
+
queueTimeOutUrl: string;
|
|
233
|
+
/**
|
|
234
|
+
* Comments sent along with the transaction (up to 100 characters).
|
|
235
|
+
* Daraja field: Remarks (String)
|
|
236
|
+
* Sample: ok
|
|
237
|
+
*/
|
|
238
|
+
remarks?: string;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Synchronous response from Daraja confirming the request was received.
|
|
242
|
+
* This is NOT the balance data — balance arrives via async callback to ResultURL.
|
|
243
|
+
*
|
|
244
|
+
* ResponseCode "0" = request accepted for processing.
|
|
245
|
+
*/
|
|
246
|
+
interface AccountBalanceResponse {
|
|
247
|
+
/** Unique identifier of the request. Auto-generated by M-PESA. */
|
|
248
|
+
OriginatorConversationID: string;
|
|
249
|
+
/** Unique identifier generated by M-PESA for this request */
|
|
250
|
+
ConversationID: string;
|
|
251
|
+
/** "0" = request accepted by Mobile Money */
|
|
252
|
+
ResponseCode: string;
|
|
253
|
+
/** Description of the ResponseCode */
|
|
254
|
+
ResponseDescription: string;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* AccountBalance result parameter key names as documented by Daraja.
|
|
258
|
+
*/
|
|
259
|
+
type AccountBalanceResultParameterKey = 'AccountBalance' | 'BOCompletedTime';
|
|
260
|
+
/**
|
|
261
|
+
* A single result parameter entry from the Daraja callback.
|
|
262
|
+
*/
|
|
263
|
+
interface AccountBalanceResultParameter {
|
|
264
|
+
Key: AccountBalanceResultParameterKey | string;
|
|
265
|
+
Value: string | number;
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* The ReferenceItem from the async callback.
|
|
269
|
+
* Key is typically "QueueTimeoutURL" as documented.
|
|
270
|
+
*/
|
|
271
|
+
interface AccountBalanceReferenceItem {
|
|
272
|
+
Key: string;
|
|
273
|
+
Value: string;
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Full async callback payload POSTed to your ResultURL after processing.
|
|
277
|
+
*
|
|
278
|
+
* ResultCode 0 = success; non-zero = failure.
|
|
279
|
+
*
|
|
280
|
+
* ResultParameters.ResultParameter contains:
|
|
281
|
+
* - AccountBalance: pipe-delimited balance string for all accounts
|
|
282
|
+
* - BOCompletedTime: completion timestamp (format: YYYYMMDDHHmmss)
|
|
283
|
+
*
|
|
284
|
+
* Ref: Callback Result Payload — Daraja Account Balance docs
|
|
285
|
+
*/
|
|
286
|
+
interface AccountBalanceResult {
|
|
287
|
+
Result: {
|
|
288
|
+
/**
|
|
289
|
+
* ResultType:
|
|
290
|
+
* "0" = completed
|
|
291
|
+
* "1" = waiting for further messages
|
|
292
|
+
*/
|
|
293
|
+
ResultType: string | number;
|
|
294
|
+
/**
|
|
295
|
+
* Result code indicating success or failure.
|
|
296
|
+
* 0 = success; see ACCOUNT_BALANCE_ERROR_CODES for failure codes.
|
|
297
|
+
* Note: Daraja may return this as string "0" or number 0 on success.
|
|
298
|
+
*/
|
|
299
|
+
ResultCode: number | string; /** Human-readable description of the result */
|
|
300
|
+
ResultDesc: string; /** Unique identifier from the original request */
|
|
301
|
+
OriginatorConversationID: string; /** Unique identifier generated by M-PESA */
|
|
302
|
+
ConversationID: string; /** M-PESA transaction identifier */
|
|
303
|
+
TransactionID: string; /** Balance data — only present on success (ResultCode 0) */
|
|
304
|
+
ResultParameters?: {
|
|
305
|
+
/**
|
|
306
|
+
* Can be an array (multiple params) or a single object (Daraja inconsistency).
|
|
307
|
+
* Use getAccountBalanceParam() to handle both forms safely.
|
|
308
|
+
*/
|
|
309
|
+
ResultParameter: AccountBalanceResultParameter[] | AccountBalanceResultParameter;
|
|
310
|
+
}; /** Reference data Daraja records in transaction logs */
|
|
311
|
+
ReferenceData?: {
|
|
312
|
+
ReferenceItem: AccountBalanceReferenceItem | AccountBalanceReferenceItem[];
|
|
313
|
+
};
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
//#endregion
|
|
317
|
+
//#region src/mpesa/b2b-express-checkout/types.d.ts
|
|
318
|
+
/**
|
|
319
|
+
* src/mpesa/b2b-express-checkout/types.ts
|
|
320
|
+
*
|
|
321
|
+
* B2B Express Checkout (USSD Push to Till) type definitions.
|
|
322
|
+
* Strictly aligned with Safaricom Daraja B2B Express Checkout API documentation.
|
|
323
|
+
*
|
|
324
|
+
* Endpoint: POST https://sandbox.safaricom.co.ke/v1/ussdpush/get-msisdn
|
|
325
|
+
*
|
|
326
|
+
* Flow:
|
|
327
|
+
* 1. Vendor initiates USSD push via Daraja
|
|
328
|
+
* 2. Merchant receives USSD prompt on their till
|
|
329
|
+
* 3. Merchant enters Operator ID + M-PESA PIN
|
|
330
|
+
* 4. M-PESA debits merchant, credits vendor
|
|
331
|
+
* 5. Daraja POSTs callback to your callbackUrl
|
|
332
|
+
*/
|
|
333
|
+
/**
|
|
334
|
+
* Request payload for B2B Express Checkout USSD Push.
|
|
335
|
+
*
|
|
336
|
+
* Daraja payload shape (all field names are camelCase except RequestRefID):
|
|
337
|
+
* {
|
|
338
|
+
* "primaryShortCode": "000001",
|
|
339
|
+
* "receiverShortCode": "000002",
|
|
340
|
+
* "amount": "100", ← sent as string per Daraja spec
|
|
341
|
+
* "paymentRef": "paymentRef",
|
|
342
|
+
* "callbackUrl": "https://...",
|
|
343
|
+
* "partnerName": "Vendor",
|
|
344
|
+
* "RequestRefID": "uuid" ← PascalCase per Daraja spec
|
|
345
|
+
* }
|
|
346
|
+
*/
|
|
347
|
+
interface B2BExpressCheckoutRequest {
|
|
348
|
+
/**
|
|
349
|
+
* Debit party — the merchant's till number that will be charged.
|
|
350
|
+
* Daraja field: primaryShortCode
|
|
351
|
+
*/
|
|
352
|
+
primaryShortCode: string;
|
|
353
|
+
/**
|
|
354
|
+
* Credit party — the vendor's Paybill account that will receive funds.
|
|
355
|
+
* Daraja field: receiverShortCode
|
|
356
|
+
*/
|
|
357
|
+
receiverShortCode: string;
|
|
358
|
+
/**
|
|
359
|
+
* Amount to send. Must be a whole number ≥ 1.
|
|
360
|
+
* Sent as a string in the Daraja payload (e.g. "100").
|
|
361
|
+
* Daraja field: amount
|
|
362
|
+
*/
|
|
363
|
+
amount: number;
|
|
364
|
+
/**
|
|
365
|
+
* Payment reference shown in the merchant's USSD prompt.
|
|
366
|
+
* Daraja field: paymentRef
|
|
367
|
+
*/
|
|
368
|
+
paymentRef: string;
|
|
369
|
+
/**
|
|
370
|
+
* Publicly accessible URL where Daraja POSTs the transaction result.
|
|
371
|
+
* Daraja field: callbackUrl
|
|
372
|
+
*/
|
|
373
|
+
callbackUrl: string;
|
|
374
|
+
/**
|
|
375
|
+
* Vendor's friendly name shown in the merchant's USSD prompt:
|
|
376
|
+
* "You are about to send Ksh {{amount}} to {{partnerName}}..."
|
|
377
|
+
* Daraja field: partnerName
|
|
378
|
+
*/
|
|
379
|
+
partnerName: string;
|
|
380
|
+
/**
|
|
381
|
+
* Unique identifier for this request — used for idempotency.
|
|
382
|
+
* Auto-generated (UUID v4) if not provided.
|
|
383
|
+
* Daraja field: RequestRefID (PascalCase per Daraja spec)
|
|
384
|
+
*/
|
|
385
|
+
requestRefId?: string;
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Synchronous acknowledgement returned immediately by Daraja.
|
|
389
|
+
*
|
|
390
|
+
* Daraja response shape:
|
|
391
|
+
* {
|
|
392
|
+
* "code": "0",
|
|
393
|
+
* "status": "USSD Initiated Successfully"
|
|
394
|
+
* }
|
|
395
|
+
*
|
|
396
|
+
* code "0" means the USSD push was initiated. The actual transaction result
|
|
397
|
+
* comes later via the callbackUrl.
|
|
398
|
+
*/
|
|
399
|
+
interface B2BExpressCheckoutResponse {
|
|
400
|
+
/** "0" = USSD push initiated successfully */
|
|
401
|
+
code: string;
|
|
402
|
+
/** Human-readable status, e.g. "USSD Initiated Successfully" */
|
|
403
|
+
status: string;
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Callback when the merchant CANCELLED the USSD prompt.
|
|
407
|
+
*
|
|
408
|
+
* Daraja callback shape:
|
|
409
|
+
* {
|
|
410
|
+
* "resultCode": "4001",
|
|
411
|
+
* "resultDesc": "User cancelled transaction",
|
|
412
|
+
* "requestId": "c2a9ba32-9e11-4b90-892c-7bc54944609a",
|
|
413
|
+
* "amount": "71.0",
|
|
414
|
+
* "paymentReference": "MAndbubry3hi"
|
|
415
|
+
* }
|
|
416
|
+
*/
|
|
417
|
+
interface B2BExpressCheckoutCallbackCancelled {
|
|
418
|
+
/** "4001" for user cancellation */
|
|
419
|
+
resultCode: string;
|
|
420
|
+
resultDesc: string;
|
|
421
|
+
requestId: string;
|
|
422
|
+
/** Amount as a string, e.g. "71.0" */
|
|
423
|
+
amount: string;
|
|
424
|
+
/** The payment reference from the original request */
|
|
425
|
+
paymentReference: string;
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* Callback when the M-PESA transaction SUCCEEDED.
|
|
429
|
+
*
|
|
430
|
+
* Daraja callback shape:
|
|
431
|
+
* {
|
|
432
|
+
* "resultCode": "0",
|
|
433
|
+
* "resultDesc": "The service request is processed successfully.",
|
|
434
|
+
* "amount": "71.0",
|
|
435
|
+
* "requestId": "404e1aec-19e0-4ce3-973d-bd92e94c8021",
|
|
436
|
+
* "resultType": "0",
|
|
437
|
+
* "conversationID":"AG_20230426_2010434680d9f5a73766",
|
|
438
|
+
* "transactionId": "RDQ01NFT1Q",
|
|
439
|
+
* "status": "SUCCESS"
|
|
440
|
+
* }
|
|
441
|
+
*/
|
|
442
|
+
interface B2BExpressCheckoutCallbackSuccess {
|
|
443
|
+
/** "0" */
|
|
444
|
+
resultCode: string;
|
|
445
|
+
resultDesc: string;
|
|
446
|
+
/** Amount as a string, e.g. "71.0" */
|
|
447
|
+
amount: string;
|
|
448
|
+
requestId: string;
|
|
449
|
+
/** Usually "0" */
|
|
450
|
+
resultType: string;
|
|
451
|
+
/** M-PESA conversation ID, e.g. "AG_20230426_..." */
|
|
452
|
+
conversationID: string;
|
|
453
|
+
/** M-PESA receipt number, e.g. "RDQ01NFT1Q" */
|
|
454
|
+
transactionId: string;
|
|
455
|
+
/** "SUCCESS" */
|
|
456
|
+
status: string;
|
|
457
|
+
}
|
|
458
|
+
/**
|
|
459
|
+
* Callback for any non-zero, non-cancelled failure
|
|
460
|
+
* (e.g. KYC failure, USSD network error, missing nominated number).
|
|
461
|
+
*
|
|
462
|
+
* Error codes documented by Daraja:
|
|
463
|
+
* 4102 — Merchant KYC failure
|
|
464
|
+
* 4104 — Missing nominated number
|
|
465
|
+
* 4201 — USSD network error
|
|
466
|
+
* 4203 — USSD exception error
|
|
467
|
+
*/
|
|
468
|
+
interface B2BExpressCheckoutCallbackFailed {
|
|
469
|
+
resultCode: string;
|
|
470
|
+
resultDesc: string;
|
|
471
|
+
requestId: string;
|
|
472
|
+
amount: string;
|
|
473
|
+
}
|
|
474
|
+
/**
|
|
475
|
+
* Union of all possible callback payload shapes.
|
|
476
|
+
* Discriminate on `resultCode`:
|
|
477
|
+
* "0" → B2BExpressCheckoutCallbackSuccess
|
|
478
|
+
* "4001" → B2BExpressCheckoutCallbackCancelled
|
|
479
|
+
* other → B2BExpressCheckoutCallbackFailed
|
|
480
|
+
*/
|
|
481
|
+
type B2BExpressCheckoutCallback = B2BExpressCheckoutCallbackSuccess | B2BExpressCheckoutCallbackCancelled | B2BExpressCheckoutCallbackFailed;
|
|
482
|
+
//#endregion
|
|
483
|
+
//#region src/mpesa/b2c/types.d.ts
|
|
484
|
+
/**
|
|
485
|
+
* src/mpesa/b2c/types.ts
|
|
486
|
+
*
|
|
487
|
+
* Strictly aligned with Safaricom Daraja B2C Account Top Up API documentation.
|
|
488
|
+
* Endpoint: POST /mpesa/b2b/v1/paymentrequest
|
|
489
|
+
*
|
|
490
|
+
* Only CommandID = "BusinessPayToBulk" is documented and supported.
|
|
491
|
+
* SenderIdentifierType and RecieverIdentifierType are always "4" per docs.
|
|
492
|
+
*/
|
|
493
|
+
/**
|
|
494
|
+
* The only CommandID supported by the B2C Account Top Up API.
|
|
495
|
+
* Docs: "Use BusinessPayToBulk only"
|
|
496
|
+
*/
|
|
497
|
+
type B2CCommandID = 'BusinessPayToBulk';
|
|
498
|
+
interface B2CRequest {
|
|
499
|
+
/**
|
|
500
|
+
* Transaction type. Must be "BusinessPayToBulk".
|
|
501
|
+
* Daraja field: CommandID
|
|
502
|
+
*/
|
|
503
|
+
commandId: B2CCommandID;
|
|
504
|
+
/**
|
|
505
|
+
* Transaction amount in KES. Must be a whole number ≥ 1.
|
|
506
|
+
* Daraja field: Amount (sent as string per API spec)
|
|
507
|
+
*/
|
|
508
|
+
amount: number;
|
|
509
|
+
/**
|
|
510
|
+
* Sender shortcode — the originating business shortcode.
|
|
511
|
+
* Daraja field: PartyA
|
|
512
|
+
* SenderIdentifierType is always "4" (Organisation ShortCode) per docs.
|
|
513
|
+
*/
|
|
514
|
+
partyA: string;
|
|
515
|
+
/**
|
|
516
|
+
* Receiver shortcode — the B2C shortcode that receives the funds.
|
|
517
|
+
* Daraja field: PartyB
|
|
518
|
+
* RecieverIdentifierType is always "4" (Organisation ShortCode) per docs.
|
|
519
|
+
*/
|
|
520
|
+
partyB: string;
|
|
521
|
+
/**
|
|
522
|
+
* Account reference for the transaction (e.g. invoice or batch number).
|
|
523
|
+
* Daraja field: AccountReference
|
|
524
|
+
*/
|
|
525
|
+
accountReference: string;
|
|
526
|
+
/**
|
|
527
|
+
* Optional. Customer phone number on whose behalf the transfer is made.
|
|
528
|
+
* Format: 254XXXXXXXXX
|
|
529
|
+
* Daraja field: Requester
|
|
530
|
+
*/
|
|
531
|
+
requester?: string;
|
|
532
|
+
/**
|
|
533
|
+
* Additional remarks for the transaction. Up to 100 characters.
|
|
534
|
+
* Daraja field: Remarks
|
|
535
|
+
*/
|
|
536
|
+
remarks?: string;
|
|
537
|
+
/**
|
|
538
|
+
* URL Safaricom calls with the final async result after processing.
|
|
539
|
+
* Must be publicly accessible. HTTPS required in production.
|
|
540
|
+
* Daraja field: ResultURL
|
|
541
|
+
*/
|
|
542
|
+
resultUrl: string;
|
|
543
|
+
/**
|
|
544
|
+
* URL Safaricom calls when the request times out in the queue.
|
|
545
|
+
* Must be publicly accessible. HTTPS required in production.
|
|
546
|
+
* Daraja field: QueueTimeOutURL
|
|
547
|
+
*/
|
|
548
|
+
queueTimeOutUrl: string;
|
|
549
|
+
}
|
|
550
|
+
interface B2CResponse {
|
|
551
|
+
/**
|
|
552
|
+
* Unique request identifier assigned by Daraja upon successful submission.
|
|
553
|
+
* Daraja field: OriginatorConversationID
|
|
554
|
+
*/
|
|
555
|
+
OriginatorConversationID: string;
|
|
556
|
+
/**
|
|
557
|
+
* Unique request identifier assigned by M-Pesa.
|
|
558
|
+
* Daraja field: ConversationID
|
|
559
|
+
*/
|
|
560
|
+
ConversationID: string;
|
|
561
|
+
/**
|
|
562
|
+
* "0" indicates the request was accepted for processing.
|
|
563
|
+
* Daraja field: ResponseCode
|
|
564
|
+
*/
|
|
565
|
+
ResponseCode: string;
|
|
566
|
+
/**
|
|
567
|
+
* Human-readable submission status description.
|
|
568
|
+
* Daraja field: ResponseDescription
|
|
569
|
+
*/
|
|
570
|
+
ResponseDescription: string;
|
|
571
|
+
}
|
|
572
|
+
/**
|
|
573
|
+
* Documented result parameter keys for B2C Account Top Up transactions.
|
|
574
|
+
* Source: Safaricom Daraja B2C Account Top Up — Successful Result Parameters.
|
|
575
|
+
*
|
|
576
|
+
* `(string & {})` is used as a catch-all so:
|
|
577
|
+
* - Named literals appear in IntelliSense/autocomplete.
|
|
578
|
+
* - Future undocumented keys from Daraja are still accepted at runtime.
|
|
579
|
+
*/
|
|
580
|
+
type B2CResultParameterKey = 'DebitAccountBalance' | 'Amount' | 'Currency' | 'ReceiverPartyPublicName' | 'TransactionCompletedTime' | 'DebitPartyCharges' | (string & {});
|
|
581
|
+
interface B2CResultParameter {
|
|
582
|
+
Key: B2CResultParameterKey;
|
|
583
|
+
Value: string | number;
|
|
584
|
+
}
|
|
585
|
+
interface B2CResult {
|
|
586
|
+
Result: {
|
|
587
|
+
/**
|
|
588
|
+
* Usually "0" for success. Docs show "0" (string) on success,
|
|
589
|
+
* numeric (e.g. 2001) on failure — typed as both for safety.
|
|
590
|
+
*/
|
|
591
|
+
ResultType: string | number;
|
|
592
|
+
/**
|
|
593
|
+
* "0" or 0 = success; non-zero = failure.
|
|
594
|
+
* Docs show string "0" on success, number 2001 on failure.
|
|
595
|
+
*/
|
|
596
|
+
ResultCode: string | number; /** Human-readable result description */
|
|
597
|
+
ResultDesc: string;
|
|
598
|
+
OriginatorConversationID: string;
|
|
599
|
+
ConversationID: string;
|
|
600
|
+
TransactionID: string;
|
|
601
|
+
ResultParameters?: {
|
|
602
|
+
ResultParameter: B2CResultParameter | B2CResultParameter[];
|
|
603
|
+
};
|
|
604
|
+
ReferenceData?: {
|
|
605
|
+
ReferenceItem: {
|
|
606
|
+
Key: string;
|
|
607
|
+
Value?: string;
|
|
608
|
+
} | Array<{
|
|
609
|
+
Key: string;
|
|
610
|
+
Value?: string;
|
|
611
|
+
}>;
|
|
612
|
+
};
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
//#endregion
|
|
616
|
+
//#region src/mpesa/b2c-disbursement/types.d.ts
|
|
617
|
+
/**
|
|
618
|
+
* src/mpesa/b2c-disbursement/types.ts
|
|
619
|
+
|
|
620
|
+
// ── Command IDs ───────────────────────────────────────────────────────────────
|
|
621
|
+
|
|
622
|
+
/**
|
|
623
|
+
* Supported CommandIDs for B2C Disbursement.
|
|
624
|
+
* Source: Safaricom Daraja B2C API documentation.
|
|
625
|
+
*/
|
|
626
|
+
type B2CDisbursementCommandID = 'BusinessPayment' | 'SalaryPayment' | 'PromotionPayment';
|
|
627
|
+
interface B2CDisbursementRequest {
|
|
628
|
+
/**
|
|
629
|
+
* Unique request ID from the merchant.
|
|
630
|
+
* Daraja field: OriginatorConversationID
|
|
631
|
+
*/
|
|
632
|
+
/** Auto-generated when omitted (via Mpesa client idempotency helper). */
|
|
633
|
+
originatorConversationId?: string;
|
|
634
|
+
/**
|
|
635
|
+
* Transaction type.
|
|
636
|
+
* Daraja field: CommandID
|
|
637
|
+
*/
|
|
638
|
+
commandId: B2CDisbursementCommandID;
|
|
639
|
+
/**
|
|
640
|
+
* Transaction amount in KES.
|
|
641
|
+
* Daraja field: Amount
|
|
642
|
+
*/
|
|
643
|
+
amount: number;
|
|
644
|
+
/**
|
|
645
|
+
* Sending organisation shortcode.
|
|
646
|
+
* Daraja field: PartyA
|
|
647
|
+
*/
|
|
648
|
+
partyA: string;
|
|
649
|
+
/**
|
|
650
|
+
* Receiving customer MSISDN (2547XXXXXXXX).
|
|
651
|
+
* Daraja field: PartyB
|
|
652
|
+
*/
|
|
653
|
+
partyB: string;
|
|
654
|
+
/**
|
|
655
|
+
* Additional transaction info (2–100 characters).
|
|
656
|
+
* Daraja field: Remarks
|
|
657
|
+
*/
|
|
658
|
+
remarks: string;
|
|
659
|
+
/**
|
|
660
|
+
* URL Safaricom calls with the async result.
|
|
661
|
+
* Daraja field: ResultURL
|
|
662
|
+
*/
|
|
663
|
+
resultUrl: string;
|
|
664
|
+
/**
|
|
665
|
+
* URL Safaricom calls on queue timeout.
|
|
666
|
+
* Daraja field: QueueTimeOutURL
|
|
667
|
+
*/
|
|
668
|
+
queueTimeOutUrl: string;
|
|
669
|
+
/**
|
|
670
|
+
* Optional additional info.
|
|
671
|
+
* Daraja field: Occassion (sic — preserved from Daraja docs)
|
|
672
|
+
*/
|
|
673
|
+
occasion?: string;
|
|
674
|
+
}
|
|
675
|
+
interface B2CDisbursementResponse {
|
|
676
|
+
/** Unique request ID assigned by M-Pesa */
|
|
677
|
+
ConversationID: string;
|
|
678
|
+
/** Merchant-supplied request ID echoed back */
|
|
679
|
+
OriginatorConversationID: string;
|
|
680
|
+
/** "0" = accepted */
|
|
681
|
+
ResponseCode: string;
|
|
682
|
+
/** Human-readable submission status */
|
|
683
|
+
ResponseDescription: string;
|
|
684
|
+
}
|
|
685
|
+
interface B2CDisbursementResultParameter {
|
|
686
|
+
Key: B2CDisbursementResultParameterKey;
|
|
687
|
+
Value: string | number;
|
|
688
|
+
}
|
|
689
|
+
/**
|
|
690
|
+
* Known result parameter keys from Daraja B2C success callback.
|
|
691
|
+
*/
|
|
692
|
+
type B2CDisbursementResultParameterKey = 'TransactionAmount' | 'TransactionReceipt' | 'ReceiverPartyPublicName' | 'TransactionCompletedDateTime' | 'B2CUtilityAccountAvailableFunds' | 'B2CWorkingAccountAvailableFunds' | 'B2CRecipientIsRegisteredCustomer' | 'B2CChargesPaidAccountAvailableFunds' | (string & {});
|
|
693
|
+
interface B2CDisbursementResult {
|
|
694
|
+
Result: {
|
|
695
|
+
ResultType: number;
|
|
696
|
+
ResultCode: number | string;
|
|
697
|
+
ResultDesc: string;
|
|
698
|
+
OriginatorConversationID: string;
|
|
699
|
+
ConversationID: string;
|
|
700
|
+
TransactionID: string;
|
|
701
|
+
ResultParameters?: {
|
|
702
|
+
ResultParameter: B2CDisbursementResultParameter | B2CDisbursementResultParameter[];
|
|
703
|
+
};
|
|
704
|
+
ReferenceData?: {
|
|
705
|
+
ReferenceItem: {
|
|
706
|
+
Key: string;
|
|
707
|
+
Value?: string;
|
|
708
|
+
} | Array<{
|
|
709
|
+
Key: string;
|
|
710
|
+
Value?: string;
|
|
711
|
+
}>;
|
|
712
|
+
};
|
|
713
|
+
};
|
|
714
|
+
}
|
|
715
|
+
//#endregion
|
|
716
|
+
//#region src/mpesa/c2b/types.d.ts
|
|
717
|
+
/**
|
|
718
|
+
* src/mpesa/c2b/types.ts
|
|
719
|
+
*
|
|
720
|
+
* Customer to Business (C2B) type definitions.
|
|
721
|
+
* Strictly aligned with Safaricom Daraja C2B Register URL API documentation.
|
|
722
|
+
*
|
|
723
|
+
* Docs: https://developer.safaricom.co.ke/APIs/CustomerToBusinessRegisterURL
|
|
724
|
+
*/
|
|
725
|
+
type C2BApiVersion = 'v1' | 'v2';
|
|
726
|
+
/**
|
|
727
|
+
* ResponseType for Register URL.
|
|
728
|
+
*
|
|
729
|
+
* Determines what M-PESA does when the Validation URL is unreachable.
|
|
730
|
+
*
|
|
731
|
+
* IMPORTANT (per docs): Must be sentence case — "Completed" or "Cancelled".
|
|
732
|
+
* ✓ "Completed" ✗ "COMPLETED" ✗ "completed"
|
|
733
|
+
* ✓ "Cancelled" ✗ "CANCELLED" ✗ "cancelled"
|
|
734
|
+
*/
|
|
735
|
+
type C2BResponseType = 'Completed' | 'Cancelled';
|
|
736
|
+
/**
|
|
737
|
+
* Request body for C2B Register URL API.
|
|
738
|
+
*
|
|
739
|
+
* Daraja payload shape (v1):
|
|
740
|
+
* {
|
|
741
|
+
* "ShortCode": "601426",
|
|
742
|
+
* "ResponseType": "Completed",
|
|
743
|
+
* "ConfirmationURL": "https://yourdomain.com/confirm",
|
|
744
|
+
* "ValidationURL": "https://yourdomain.com/validate"
|
|
745
|
+
* }
|
|
746
|
+
*/
|
|
747
|
+
interface C2BRegisterUrlRequest {
|
|
748
|
+
/** Paybill or Till shortcode */
|
|
749
|
+
shortCode: string;
|
|
750
|
+
/**
|
|
751
|
+
* Default action when Validation URL is unreachable.
|
|
752
|
+
* Must be sentence-case: "Completed" or "Cancelled".
|
|
753
|
+
* Per docs: "The words Cancelled and Completed must be in Sentence case."
|
|
754
|
+
*/
|
|
755
|
+
responseType: C2BResponseType;
|
|
756
|
+
/**
|
|
757
|
+
* URL that receives the confirmation callback after payment completes.
|
|
758
|
+
* Must be publicly accessible and internet-reachable.
|
|
759
|
+
* Production requires HTTPS; Sandbox allows HTTP.
|
|
760
|
+
*/
|
|
761
|
+
confirmationUrl: string;
|
|
762
|
+
/**
|
|
763
|
+
* URL that receives the validation callback before payment completes.
|
|
764
|
+
* Only called when external validation is enabled on the shortcode.
|
|
765
|
+
* To enable external validation, email apisupport@safaricom.co.ke.
|
|
766
|
+
*/
|
|
767
|
+
validationUrl: string;
|
|
768
|
+
/** API version to use — defaults to "v1" (documented endpoint) */
|
|
769
|
+
apiVersion?: C2BApiVersion;
|
|
770
|
+
}
|
|
771
|
+
/**
|
|
772
|
+
* Shared Daraja C2B response fields (Register URL, Simulate, etc.).
|
|
773
|
+
*
|
|
774
|
+
* Note: "OriginatorCoversationID" — Daraja spells "Conversation" as
|
|
775
|
+
* "Coversation" in the actual API response. We preserve the typo to
|
|
776
|
+
* match the real payload.
|
|
777
|
+
*/
|
|
778
|
+
interface C2BBaseResponse {
|
|
779
|
+
/** Global unique identifier for this request (note Daraja's spelling typo) */
|
|
780
|
+
OriginatorCoversationID: string;
|
|
781
|
+
/** "0" = success */
|
|
782
|
+
ResponseCode: string;
|
|
783
|
+
ResponseDescription: string;
|
|
784
|
+
}
|
|
785
|
+
/**
|
|
786
|
+
* Response from C2B Register URL API.
|
|
787
|
+
*/
|
|
788
|
+
interface C2BRegisterUrlResponse extends C2BBaseResponse {}
|
|
789
|
+
/**
|
|
790
|
+
* CommandID for C2B simulation.
|
|
791
|
+
*
|
|
792
|
+
* "CustomerPayBillOnline" — payment to a Paybill number
|
|
793
|
+
* "CustomerBuyGoodsOnline" — payment to a Till number
|
|
794
|
+
*/
|
|
795
|
+
type C2BCommandID = 'CustomerPayBillOnline' | 'CustomerBuyGoodsOnline';
|
|
796
|
+
/**
|
|
797
|
+
* Request body for C2B Simulate API (Sandbox only).
|
|
798
|
+
*
|
|
799
|
+
* Daraja payload shape:
|
|
800
|
+
* {
|
|
801
|
+
* "ShortCode": 600984, ← numeric
|
|
802
|
+
* "CommandID": "CustomerPayBillOnline",
|
|
803
|
+
* "Amount": 1, ← numeric, whole number
|
|
804
|
+
* "Msisdn": 254708374149, ← numeric
|
|
805
|
+
* "BillRefNumber": "TestRef" ← omit entirely for CustomerBuyGoodsOnline
|
|
806
|
+
* }
|
|
807
|
+
*/
|
|
808
|
+
interface C2BSimulateRequest {
|
|
809
|
+
/** Paybill or Till shortcode — sent as a number in the payload */
|
|
810
|
+
shortCode: string | number;
|
|
811
|
+
/** Transaction type — Paybill or BuyGoods */
|
|
812
|
+
commandId: C2BCommandID;
|
|
813
|
+
/** Amount in KES — whole numbers only; fractional values are rounded */
|
|
814
|
+
amount: number;
|
|
815
|
+
/** Sender MSISDN. Sandbox test number: 254708374149 */
|
|
816
|
+
msisdn: string | number;
|
|
817
|
+
/**
|
|
818
|
+
* Account reference for Paybill payments.
|
|
819
|
+
* MUST be omitted (not null, not "") for CustomerBuyGoodsOnline.
|
|
820
|
+
* Per docs: "null for customer buy goods"
|
|
821
|
+
*/
|
|
822
|
+
billRefNumber?: string | null;
|
|
823
|
+
/** API version to use — defaults to "v2" */
|
|
824
|
+
apiVersion?: C2BApiVersion;
|
|
825
|
+
}
|
|
826
|
+
/** Response from C2B Simulate API. */
|
|
827
|
+
interface C2BSimulateResponse extends C2BBaseResponse {}
|
|
828
|
+
/**
|
|
829
|
+
* Payload POSTed to your ValidationURL by M-PESA.
|
|
830
|
+
*
|
|
831
|
+
* Only received when external validation is enabled on the shortcode.
|
|
832
|
+
* OrgAccountBalance is BLANK for validation requests.
|
|
833
|
+
*
|
|
834
|
+
* Sample from Daraja docs:
|
|
835
|
+
* {
|
|
836
|
+
* "TransactionType": "Pay Bill",
|
|
837
|
+
* "TransID": "RKTQDM7W6S",
|
|
838
|
+
* "TransTime": "20191122063845",
|
|
839
|
+
* "TransAmount": "10",
|
|
840
|
+
* "BusinessShortCode": "600638",
|
|
841
|
+
* "BillRefNumber": "invoice008",
|
|
842
|
+
* "InvoiceNumber": "",
|
|
843
|
+
* "OrgAccountBalance": "",
|
|
844
|
+
* "ThirdPartyTransID": "",
|
|
845
|
+
* "MSISDN": "25470****149",
|
|
846
|
+
* "FirstName": "John",
|
|
847
|
+
* "MiddleName": "",
|
|
848
|
+
* "LastName": "Doe"
|
|
849
|
+
* }
|
|
850
|
+
*/
|
|
851
|
+
interface C2BValidationPayload {
|
|
852
|
+
/**
|
|
853
|
+
* Transaction type as received from M-PESA.
|
|
854
|
+
* Per docs: "Pay Bill" or "Buy Goods"
|
|
855
|
+
* (NOT the CommandID strings "CustomerPayBillOnline" / "CustomerBuyGoodsOnline")
|
|
856
|
+
*/
|
|
857
|
+
TransactionType: string;
|
|
858
|
+
/** Unique M-PESA transaction ID */
|
|
859
|
+
TransID: string;
|
|
860
|
+
/** Transaction timestamp: YYYYMMDDHHmmss */
|
|
861
|
+
TransTime: string;
|
|
862
|
+
/**
|
|
863
|
+
* Amount the customer is paying.
|
|
864
|
+
* Per docs: whole numbers only.
|
|
865
|
+
*/
|
|
866
|
+
TransAmount: string;
|
|
867
|
+
/** Your shortcode (5–6 digits) */
|
|
868
|
+
BusinessShortCode: string;
|
|
869
|
+
/** Account reference (Paybill only) — up to 20 alphanumeric chars */
|
|
870
|
+
BillRefNumber: string;
|
|
871
|
+
/** Invoice number — usually empty */
|
|
872
|
+
InvoiceNumber: string;
|
|
873
|
+
/**
|
|
874
|
+
* Blank for validation requests per docs.
|
|
875
|
+
* Contains new balance after payment for confirmation requests.
|
|
876
|
+
*/
|
|
877
|
+
OrgAccountBalance: string;
|
|
878
|
+
/** Third-party transaction ID. Can echo back in your validation response. */
|
|
879
|
+
ThirdPartyTransID: string;
|
|
880
|
+
/**
|
|
881
|
+
* Masked mobile number of the customer.
|
|
882
|
+
* Format example from docs: "25470****149"
|
|
883
|
+
*/
|
|
884
|
+
MSISDN: string;
|
|
885
|
+
FirstName: string;
|
|
886
|
+
MiddleName: string;
|
|
887
|
+
LastName: string;
|
|
888
|
+
}
|
|
889
|
+
/**
|
|
890
|
+
* Result codes for validation response.
|
|
891
|
+
*
|
|
892
|
+
* Per Daraja documentation:
|
|
893
|
+
* "0" → Accept the payment
|
|
894
|
+
* "C2B00011" → Invalid MSISDN
|
|
895
|
+
* "C2B00012" → Invalid Account Number
|
|
896
|
+
* "C2B00013" → Invalid Amount
|
|
897
|
+
* "C2B00014" → Invalid KYC Details
|
|
898
|
+
* "C2B00015" → Invalid Shortcode
|
|
899
|
+
* "C2B00016" → Other Error
|
|
900
|
+
*/
|
|
901
|
+
type C2BValidationResultCode = '0' | 'C2B00011' | 'C2B00012' | 'C2B00013' | 'C2B00014' | 'C2B00015' | 'C2B00016';
|
|
902
|
+
/**
|
|
903
|
+
* Response your ValidationURL must return to M-PESA.
|
|
904
|
+
*
|
|
905
|
+
* To accept (per docs):
|
|
906
|
+
* { "ResultCode": "0", "ResultDesc": "Accepted" }
|
|
907
|
+
*
|
|
908
|
+
* To reject (per docs):
|
|
909
|
+
* { "ResultCode": "C2B00011", "ResultDesc": "Rejected" }
|
|
910
|
+
*
|
|
911
|
+
* Per docs, you can also echo back ThirdPartyTransID.
|
|
912
|
+
*/
|
|
913
|
+
interface C2BValidationResponse {
|
|
914
|
+
/** "0" to accept; any C2B error code to reject */
|
|
915
|
+
ResultCode: C2BValidationResultCode;
|
|
916
|
+
/** "Accepted" or "Rejected" */
|
|
917
|
+
ResultDesc: 'Accepted' | 'Rejected';
|
|
918
|
+
/**
|
|
919
|
+
* Optional — echo back the ThirdPartyTransID from the validation request.
|
|
920
|
+
* M-PESA will include it in the subsequent confirmation callback.
|
|
921
|
+
*/
|
|
922
|
+
ThirdPartyTransID?: string;
|
|
923
|
+
}
|
|
924
|
+
/**
|
|
925
|
+
* Payload POSTed to your ConfirmationURL by M-PESA after payment completes.
|
|
926
|
+
*
|
|
927
|
+
* OrgAccountBalance contains the NEW balance after this payment.
|
|
928
|
+
* This payload is only sent when the transaction completes successfully.
|
|
929
|
+
*
|
|
930
|
+
* Per docs process flow:
|
|
931
|
+
* - External Validation ON: sent after validation succeeds
|
|
932
|
+
* - External Validation OFF: sent automatically after every completed payment
|
|
933
|
+
*/
|
|
934
|
+
interface C2BConfirmationPayload {
|
|
935
|
+
/**
|
|
936
|
+
* Transaction type as received from M-PESA.
|
|
937
|
+
* Per docs: "Pay Bill" or "Buy Goods"
|
|
938
|
+
*/
|
|
939
|
+
TransactionType: string;
|
|
940
|
+
/** Unique M-PESA transaction ID */
|
|
941
|
+
TransID: string;
|
|
942
|
+
/** Transaction timestamp: YYYYMMDDHHmmss */
|
|
943
|
+
TransTime: string;
|
|
944
|
+
/** Amount transacted — whole numbers only per docs */
|
|
945
|
+
TransAmount: string;
|
|
946
|
+
/** Your shortcode (5–6 digits) */
|
|
947
|
+
BusinessShortCode: string;
|
|
948
|
+
/** Account reference (Paybill only) */
|
|
949
|
+
BillRefNumber: string;
|
|
950
|
+
/** Invoice number — usually empty */
|
|
951
|
+
InvoiceNumber: string;
|
|
952
|
+
/**
|
|
953
|
+
* New utility account balance after this payment.
|
|
954
|
+
* Blank for validation requests; populated in confirmation.
|
|
955
|
+
*/
|
|
956
|
+
OrgAccountBalance: string;
|
|
957
|
+
/** Third-party transaction ID (echoed from validation response if set) */
|
|
958
|
+
ThirdPartyTransID: string;
|
|
959
|
+
/** Masked mobile number — e.g. "25470****149" */
|
|
960
|
+
MSISDN: string;
|
|
961
|
+
FirstName: string;
|
|
962
|
+
MiddleName: string;
|
|
963
|
+
LastName: string;
|
|
964
|
+
}
|
|
965
|
+
//#endregion
|
|
966
|
+
//#region src/mpesa/reversal/types.d.ts
|
|
967
|
+
/**
|
|
968
|
+
* Keys present in the ResultParameters.ResultParameter array of a successful
|
|
969
|
+
* reversal callback, as documented by Daraja.
|
|
970
|
+
*/
|
|
971
|
+
type ReversalResultParameterKey = 'DebitAccountBalance' | 'Amount' | 'TransCompletedTime' | 'OriginalTransactionID' | 'Charge' | 'CreditPartyPublicName' | 'DebitPartyPublicName';
|
|
972
|
+
/**
|
|
973
|
+
* Parameters for the Reversals API request.
|
|
974
|
+
*
|
|
975
|
+
* Daraja request body shape:
|
|
976
|
+
* ```json
|
|
977
|
+
* {
|
|
978
|
+
* "Initiator": "apiop37",
|
|
979
|
+
* "SecurityCredential": "RC6E9WDx9X2c6z3gp0oC5Th==",
|
|
980
|
+
* "CommandID": "TransactionReversal",
|
|
981
|
+
* "TransactionID": "PDU91HIVIT",
|
|
982
|
+
* "Amount": "200",
|
|
983
|
+
* "ReceiverParty": "603021",
|
|
984
|
+
* "RecieverIdentifierType":"11",
|
|
985
|
+
* "ResultURL": "https://mydomain.com/reversal/result",
|
|
986
|
+
* "QueueTimeOutURL": "https://mydomain.com/reversal/queue",
|
|
987
|
+
* "Remarks": "Payment reversal"
|
|
988
|
+
* }
|
|
989
|
+
* ```
|
|
990
|
+
*
|
|
991
|
+
* Note: Initiator and SecurityCredential are supplied by the SDK layer;
|
|
992
|
+
* they are not part of this user-facing request interface.
|
|
993
|
+
*/
|
|
994
|
+
interface ReversalRequest {
|
|
995
|
+
/**
|
|
996
|
+
* The M-PESA receipt number of the transaction to reverse.
|
|
997
|
+
* Example: "PDU91HIVIT"
|
|
998
|
+
* Daraja field: TransactionID
|
|
999
|
+
*/
|
|
1000
|
+
transactionId: string;
|
|
1001
|
+
/**
|
|
1002
|
+
* Your organisation shortcode (Paybill or Till number).
|
|
1003
|
+
* Daraja field: ReceiverParty
|
|
1004
|
+
*/
|
|
1005
|
+
receiverParty: string;
|
|
1006
|
+
/**
|
|
1007
|
+
* Identifier type for ReceiverParty.
|
|
1008
|
+
* Per Daraja docs: MUST be "11" (Organisation/ShortCode reversal type).
|
|
1009
|
+
* This value is validated and always sent as "11".
|
|
1010
|
+
* Daraja field: RecieverIdentifierType (note Daraja's spelling)
|
|
1011
|
+
*
|
|
1012
|
+
* @default "11"
|
|
1013
|
+
*/
|
|
1014
|
+
receiverIdentifierType?: '11';
|
|
1015
|
+
/**
|
|
1016
|
+
* Amount to reverse. Must equal the original transaction amount.
|
|
1017
|
+
* Must be a whole number ≥ 1.
|
|
1018
|
+
* Daraja field: Amount (sent as string per Daraja docs sample)
|
|
1019
|
+
*/
|
|
1020
|
+
amount: number;
|
|
1021
|
+
/**
|
|
1022
|
+
* URL where Safaricom POSTs the reversal result asynchronously.
|
|
1023
|
+
* Must be publicly accessible over the internet.
|
|
1024
|
+
* Daraja field: ResultURL
|
|
1025
|
+
*/
|
|
1026
|
+
resultUrl: string;
|
|
1027
|
+
/**
|
|
1028
|
+
* URL called when the request times out in the Daraja queue.
|
|
1029
|
+
* Must be publicly accessible over the internet.
|
|
1030
|
+
* Daraja field: QueueTimeOutURL
|
|
1031
|
+
*/
|
|
1032
|
+
queueTimeOutUrl: string;
|
|
1033
|
+
/**
|
|
1034
|
+
* Short description of the reversal reason (2–100 characters).
|
|
1035
|
+
* Daraja field: Remarks
|
|
1036
|
+
* @default "Transaction Reversal"
|
|
1037
|
+
*/
|
|
1038
|
+
remarks?: string;
|
|
1039
|
+
/**
|
|
1040
|
+
* Optional occasion/reference string.
|
|
1041
|
+
* Not in the Daraja sample payload but accepted by the API.
|
|
1042
|
+
* Daraja field: Occasion
|
|
1043
|
+
*/
|
|
1044
|
+
occasion?: string;
|
|
1045
|
+
}
|
|
1046
|
+
/**
|
|
1047
|
+
* Synchronous response from the Reversals API.
|
|
1048
|
+
*
|
|
1049
|
+
* This is only an acknowledgement that the request was received.
|
|
1050
|
+
* The actual reversal result arrives asynchronously at your ResultURL.
|
|
1051
|
+
*
|
|
1052
|
+
* Daraja response shape:
|
|
1053
|
+
* ```json
|
|
1054
|
+
* {
|
|
1055
|
+
* "OriginatorConversationID": "f1e2-4b95-a71d-b30d3cdbb7a7735297",
|
|
1056
|
+
* "ConversationID": "AG_20210706_20106e9209f64bebd05b",
|
|
1057
|
+
* "ResponseCode": "0",
|
|
1058
|
+
* "ResponseDescription": "Accept the service request successfully."
|
|
1059
|
+
* }
|
|
1060
|
+
* ```
|
|
1061
|
+
*/
|
|
1062
|
+
interface ReversalResponse {
|
|
1063
|
+
/** Unique identifier for this reversal request from M-PESA */
|
|
1064
|
+
OriginatorConversationID: string;
|
|
1065
|
+
/** Unique global identifier for the transaction request */
|
|
1066
|
+
ConversationID: string;
|
|
1067
|
+
/**
|
|
1068
|
+
* "0" = request accepted successfully.
|
|
1069
|
+
* Any other value = API-level error (not reversal failure).
|
|
1070
|
+
*/
|
|
1071
|
+
ResponseCode: string;
|
|
1072
|
+
/** Human-readable acknowledgement message */
|
|
1073
|
+
ResponseDescription: string;
|
|
1074
|
+
}
|
|
1075
|
+
/**
|
|
1076
|
+
* Result parameter item in a successful reversal callback.
|
|
1077
|
+
*/
|
|
1078
|
+
interface ReversalResultParameter {
|
|
1079
|
+
Key: ReversalResultParameterKey;
|
|
1080
|
+
Value: string | number;
|
|
1081
|
+
}
|
|
1082
|
+
/**
|
|
1083
|
+
* Full async reversal result POSTed to your ResultURL after processing.
|
|
1084
|
+
*
|
|
1085
|
+
* Successful callback shape (per Daraja docs):
|
|
1086
|
+
* ```json
|
|
1087
|
+
* {
|
|
1088
|
+
* "Result": {
|
|
1089
|
+
* "ResultType": 0,
|
|
1090
|
+
* "ResultCode": 0,
|
|
1091
|
+
* "ResultDesc": "The service request is processed successfully.",
|
|
1092
|
+
* "OriginatorConversationID": "...",
|
|
1093
|
+
* "ConversationID": "AG_...",
|
|
1094
|
+
* "TransactionID": "SKE52PAWR9",
|
|
1095
|
+
* "ResultParameters": {
|
|
1096
|
+
* "ResultParameter": [
|
|
1097
|
+
* { "Key": "DebitAccountBalance", "Value": "Utility Account|KES|..." },
|
|
1098
|
+
* { "Key": "Amount", "Value": 1.00 },
|
|
1099
|
+
* { "Key": "TransCompletedTime", "Value": 20211114132711 },
|
|
1100
|
+
* { "Key": "OriginalTransactionID","Value": "SKC82PACB8" },
|
|
1101
|
+
* { "Key": "Charge", "Value": 0.00 },
|
|
1102
|
+
* { "Key": "CreditPartyPublicName","Value": "254705912645 - NICHOLAS JOHN SONGOK" },
|
|
1103
|
+
* { "Key": "DebitPartyPublicName", "Value": "600992 - Safaricom Daraja 992" }
|
|
1104
|
+
* ]
|
|
1105
|
+
* },
|
|
1106
|
+
* "ReferenceData": {
|
|
1107
|
+
* "ReferenceItem": {
|
|
1108
|
+
* "Key": "QueueTimeoutURL",
|
|
1109
|
+
* "Value": "https://..."
|
|
1110
|
+
* }
|
|
1111
|
+
* }
|
|
1112
|
+
* }
|
|
1113
|
+
* }
|
|
1114
|
+
* ```
|
|
1115
|
+
*
|
|
1116
|
+
* Failed callback shape (per Daraja docs):
|
|
1117
|
+
* ```json
|
|
1118
|
+
* {
|
|
1119
|
+
* "Result": {
|
|
1120
|
+
* "ResultType": 0,
|
|
1121
|
+
* "ResultCode": "R000002",
|
|
1122
|
+
* "ResultDesc": "The OriginalTransactionID is invalid.",
|
|
1123
|
+
* ...
|
|
1124
|
+
* }
|
|
1125
|
+
* }
|
|
1126
|
+
* ```
|
|
1127
|
+
*
|
|
1128
|
+
* Note: ResultCode is 0 (number) on success and a string like "R000002" on failure.
|
|
1129
|
+
*/
|
|
1130
|
+
interface ReversalResult {
|
|
1131
|
+
Result: {
|
|
1132
|
+
/** Status type (usually 0) */ResultType: number;
|
|
1133
|
+
/**
|
|
1134
|
+
* 0 (number) = success.
|
|
1135
|
+
* String codes like "R000002" = failure.
|
|
1136
|
+
* See REVERSAL_RESULT_CODES for all documented values.
|
|
1137
|
+
*/
|
|
1138
|
+
ResultCode: number | string; /** Human-readable result description */
|
|
1139
|
+
ResultDesc: string; /** Unique identifier for the reversal request */
|
|
1140
|
+
OriginatorConversationID: string; /** Unique identifier from M-PESA */
|
|
1141
|
+
ConversationID: string; /** M-PESA receipt number for the reversal transaction */
|
|
1142
|
+
TransactionID: string;
|
|
1143
|
+
/**
|
|
1144
|
+
* Present on success — contains transaction details.
|
|
1145
|
+
* Absent on failure.
|
|
1146
|
+
*/
|
|
1147
|
+
ResultParameters?: {
|
|
1148
|
+
ResultParameter: ReversalResultParameter[];
|
|
1149
|
+
};
|
|
1150
|
+
ReferenceData?: {
|
|
1151
|
+
ReferenceItem: {
|
|
1152
|
+
Key: string;
|
|
1153
|
+
Value: string;
|
|
1154
|
+
} | Array<{
|
|
1155
|
+
Key: string;
|
|
1156
|
+
Value: string;
|
|
1157
|
+
}>;
|
|
1158
|
+
};
|
|
1159
|
+
};
|
|
1160
|
+
}
|
|
1161
|
+
//#endregion
|
|
1162
|
+
//#region src/mpesa/tax-remittance/types.d.ts
|
|
1163
|
+
interface TaxRemittanceRequest {
|
|
1164
|
+
/**
|
|
1165
|
+
* The transaction amount to remit to KRA.
|
|
1166
|
+
* Must be a whole number ≥ 1.
|
|
1167
|
+
* Daraja field: Amount
|
|
1168
|
+
*/
|
|
1169
|
+
amount: number;
|
|
1170
|
+
/**
|
|
1171
|
+
* Your own M-PESA business shortcode from which the money is deducted.
|
|
1172
|
+
* Daraja field: PartyA
|
|
1173
|
+
*/
|
|
1174
|
+
partyA: string;
|
|
1175
|
+
/**
|
|
1176
|
+
* The KRA account to which money is credited.
|
|
1177
|
+
* For Tax Remittance, only "572572" is allowed.
|
|
1178
|
+
* Defaults to KRA_SHORTCODE ("572572") when omitted.
|
|
1179
|
+
* Daraja field: PartyB
|
|
1180
|
+
*/
|
|
1181
|
+
partyB?: string;
|
|
1182
|
+
/**
|
|
1183
|
+
* The Payment Registration Number (PRN) issued by KRA.
|
|
1184
|
+
* This is your tax declaration reference from KRA.
|
|
1185
|
+
* Daraja field: AccountReference
|
|
1186
|
+
*/
|
|
1187
|
+
accountReference: string;
|
|
1188
|
+
/**
|
|
1189
|
+
* URL where Safaricom POSTs the final result after processing.
|
|
1190
|
+
* Must be publicly accessible.
|
|
1191
|
+
* Daraja field: ResultURL
|
|
1192
|
+
*/
|
|
1193
|
+
resultUrl: string;
|
|
1194
|
+
/**
|
|
1195
|
+
* URL Safaricom calls when the request times out in the queue.
|
|
1196
|
+
* Must be publicly accessible.
|
|
1197
|
+
* Daraja field: QueueTimeOutURL
|
|
1198
|
+
*/
|
|
1199
|
+
queueTimeOutUrl: string;
|
|
1200
|
+
/**
|
|
1201
|
+
* Additional information associated with the transaction.
|
|
1202
|
+
* Optional — defaults to "Tax Remittance" when omitted.
|
|
1203
|
+
* Daraja field: Remarks
|
|
1204
|
+
*/
|
|
1205
|
+
remarks?: string;
|
|
1206
|
+
}
|
|
1207
|
+
interface TaxRemittanceResponse {
|
|
1208
|
+
/** Unique request identifier assigned by Daraja upon successful submission */
|
|
1209
|
+
OriginatorConversationID: string;
|
|
1210
|
+
/** Unique request identifier assigned by M-Pesa upon successful submission */
|
|
1211
|
+
ConversationID: string;
|
|
1212
|
+
/** "0" = successful submission */
|
|
1213
|
+
ResponseCode: string;
|
|
1214
|
+
/** Descriptive message of the submission status */
|
|
1215
|
+
ResponseDescription: string;
|
|
1216
|
+
}
|
|
1217
|
+
/**
|
|
1218
|
+
* Known result parameter keys for Tax Remittance as documented by Daraja.
|
|
1219
|
+
*
|
|
1220
|
+
* `(string & {})` is used as the catch-all so that:
|
|
1221
|
+
* - Named literals appear in IntelliSense / autocomplete.
|
|
1222
|
+
* - Any unknown future key Daraja may return is still accepted.
|
|
1223
|
+
* - The `no-redundant-type-constituents` ESLint rule is not triggered.
|
|
1224
|
+
*/
|
|
1225
|
+
type TaxRemittanceResultParameterKey = 'Amount' | 'TransactionCompletedTime' | 'ReceiverPartyPublicName' | (string & {});
|
|
1226
|
+
interface TaxRemittanceResultParameter {
|
|
1227
|
+
Key: TaxRemittanceResultParameterKey;
|
|
1228
|
+
Value: string | number;
|
|
1229
|
+
}
|
|
1230
|
+
interface TaxRemittanceResult {
|
|
1231
|
+
Result: {
|
|
1232
|
+
/**
|
|
1233
|
+
* Result type indicator.
|
|
1234
|
+
* Daraja returns "0" (string) in success callbacks.
|
|
1235
|
+
* Can also be numeric in some environments.
|
|
1236
|
+
*/
|
|
1237
|
+
ResultType: string | number;
|
|
1238
|
+
/**
|
|
1239
|
+
* 0 / "0" = success; non-zero = failure.
|
|
1240
|
+
* Daraja returns "0" (string) in success callbacks per the docs.
|
|
1241
|
+
* Failure codes (e.g. 2001) are typically returned as numbers.
|
|
1242
|
+
*/
|
|
1243
|
+
ResultCode: string | number; /** Human-readable result description */
|
|
1244
|
+
ResultDesc: string;
|
|
1245
|
+
OriginatorConversationID: string;
|
|
1246
|
+
ConversationID: string;
|
|
1247
|
+
TransactionID: string;
|
|
1248
|
+
/**
|
|
1249
|
+
* Present on successful results only.
|
|
1250
|
+
* Daraja may return ResultParameter as a single object or an array —
|
|
1251
|
+
* both shapes are handled by the webhook helpers.
|
|
1252
|
+
*/
|
|
1253
|
+
ResultParameters?: {
|
|
1254
|
+
ResultParameter: TaxRemittanceResultParameter | TaxRemittanceResultParameter[];
|
|
1255
|
+
};
|
|
1256
|
+
};
|
|
1257
|
+
}
|
|
1258
|
+
//#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 };
|