@maxkabechani/mtn-momo-sdk 0.1.0 → 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.
Files changed (40) hide show
  1. package/README.md +595 -65
  2. package/lib/cjs/cli.js +0 -0
  3. package/lib/cjs/collections.d.ts +15 -1
  4. package/lib/cjs/collections.d.ts.map +1 -1
  5. package/lib/cjs/collections.js +42 -2
  6. package/lib/cjs/collections.js.map +1 -1
  7. package/lib/cjs/common.d.ts +8 -0
  8. package/lib/cjs/common.d.ts.map +1 -1
  9. package/lib/cjs/disbursements.d.ts +15 -1
  10. package/lib/cjs/disbursements.d.ts.map +1 -1
  11. package/lib/cjs/disbursements.js +35 -0
  12. package/lib/cjs/disbursements.js.map +1 -1
  13. package/lib/cjs/index.d.ts +1 -1
  14. package/lib/cjs/index.d.ts.map +1 -1
  15. package/lib/cjs/index.js +2 -0
  16. package/lib/cjs/index.js.map +1 -1
  17. package/lib/cjs/remittance.d.ts +30 -1
  18. package/lib/cjs/remittance.d.ts.map +1 -1
  19. package/lib/cjs/remittance.js +91 -22
  20. package/lib/cjs/remittance.js.map +1 -1
  21. package/lib/esm/cli.js +0 -0
  22. package/lib/esm/collections.d.ts +15 -1
  23. package/lib/esm/collections.d.ts.map +1 -1
  24. package/lib/esm/collections.js +42 -2
  25. package/lib/esm/collections.js.map +1 -1
  26. package/lib/esm/common.d.ts +8 -0
  27. package/lib/esm/common.d.ts.map +1 -1
  28. package/lib/esm/disbursements.d.ts +15 -1
  29. package/lib/esm/disbursements.d.ts.map +1 -1
  30. package/lib/esm/disbursements.js +35 -0
  31. package/lib/esm/disbursements.js.map +1 -1
  32. package/lib/esm/index.d.ts +1 -1
  33. package/lib/esm/index.d.ts.map +1 -1
  34. package/lib/esm/index.js +2 -0
  35. package/lib/esm/index.js.map +1 -1
  36. package/lib/esm/remittance.d.ts +30 -1
  37. package/lib/esm/remittance.d.ts.map +1 -1
  38. package/lib/esm/remittance.js +92 -23
  39. package/lib/esm/remittance.js.map +1 -1
  40. package/package.json +1 -1
package/README.md CHANGED
@@ -1,17 +1,17 @@
1
1
  # MTN MoMo Node SDK (@maxkabechani/mtn-momo-sdk)
2
2
 
3
- TypeScript-first MTN Mobile Money client for Node.js. Fully compatible with official MoMo API v1.0 and v2.0.
3
+ TypeScript-first MTN Mobile Money client for Node.js. Fully compatible with the official MoMo API v1.0 and v2.0.
4
4
 
5
- This SDK provides a type-safe, developer-friendly interface for integrating MTN Mobile Money into your applications. It supports **Collections**, **Disbursements**, and **Remittance** products.
5
+ This SDK provides a type-safe, developer-friendly interface for integrating MTN Mobile Money into your applications. It supports **Collections**, **Disbursements**, **Remittance**, and **Sandbox User Provisioning**.
6
6
 
7
7
  ---
8
8
 
9
9
  ## Features
10
10
 
11
- - **Coexistence of V1 & V2**: Use stable V1 endpoints by default or opt-in to latest V2 features (e.g., `depositV2`).
12
- - **Comprehensive Coverage**: Supporting everything from simple transfers to biometric consent (BC Authorize).
13
- - **TypeScript First**: Full type definitions for all requests and responses.
14
- - **Bun & Node.js**: Optimized for modern runtimes.
11
+ - **V1 & V2 Coexistence**: Use stable V1 endpoints by default or opt-in to V2 features (`depositV2`, `refundV2`, `requestToWithdrawV2`, `cashTransfer`).
12
+ - **Comprehensive Coverage**: Request-to-pay, transfers, deposits, refunds, withdrawals, BC Authorize, OAuth2 consent, delivery notifications, and more.
13
+ - **TypeScript First**: Full type definitions for all requests, responses, and errors.
14
+ - **Bun & Node.js**: Works with modern runtimes.
15
15
 
16
16
  ---
17
17
 
@@ -25,103 +25,637 @@ bun add @maxkabechani/mtn-momo-sdk
25
25
 
26
26
  ---
27
27
 
28
- ## Quick Start (Sandbox)
28
+ ## Quick Start
29
29
 
30
30
  ### 1. Initialize the Client
31
+
31
32
  ```ts
32
33
  import { create, Environment } from "@maxkabechani/mtn-momo-sdk";
33
34
 
34
35
  const momo = create({
35
- callbackHost: "yourdomain.com", // Used for callback validation
36
- environment: Environment.SANDBOX,
36
+ callbackHost: "yourdomain.com",
37
+ environment: Environment.SANDBOX, // or Environment.PRODUCTION
37
38
  });
38
39
  ```
39
40
 
40
- ### 2. Configure a Product
41
- Each product (Collections, Disbursements, Remittance) is initialized separately:
41
+ ### 2. Provision Sandbox Credentials
42
+
43
+ Use the `Users` client to create sandbox API users, or use the CLI tool:
42
44
 
43
45
  ```ts
44
- const collections = momo.Collections({
45
- primaryKey: "your_collections_primary_key",
46
- userId: "your_user_id",
47
- userSecret: "your_user_secret",
48
- });
46
+ const users = momo.Users({ primaryKey: "YOUR_PRIMARY_KEY" });
47
+
48
+ const userId = await users.create("yourdomain.com");
49
+ const { apiKey } = await users.login(userId);
49
50
  ```
50
51
 
51
- ### 3. Generate Sandbox Credentials
52
- If you don't have a `userId` and `userSecret` yet, you can generate them using our CLI tool:
52
+ Or via CLI:
53
53
 
54
54
  ```bash
55
55
  npx momo-sandbox --host yourdomain.com --primary-key YOUR_PRIMARY_KEY
56
56
  ```
57
57
 
58
+ ### 3. Configure a Product
59
+
60
+ ```ts
61
+ const collections = momo.Collections({
62
+ primaryKey: "your_collections_primary_key",
63
+ userId: userId,
64
+ userSecret: apiKey,
65
+ });
66
+ ```
67
+
58
68
  ---
59
69
 
60
70
  ## API Reference
61
71
 
72
+ ### Common Types
73
+
74
+ ```ts
75
+ // Party identifier
76
+ interface Party {
77
+ partyIdType: "MSISDN" | "EMAIL" | "PARTY_CODE";
78
+ partyId: string;
79
+ }
80
+
81
+ // Account balance
82
+ interface Balance {
83
+ availableBalance: string;
84
+ currency: string;
85
+ }
86
+
87
+ // Basic user info
88
+ interface BasicUserInfo {
89
+ given_name: string;
90
+ family_name: string;
91
+ birthdate: string;
92
+ locale: string;
93
+ gender: string;
94
+ }
95
+
96
+ // OAuth2 consent KYC response
97
+ interface ConsentKycResponse {
98
+ sub: string;
99
+ name: string;
100
+ phone_number: string;
101
+ status: string;
102
+ // ... additional KYC fields
103
+ }
104
+
105
+ // BC Authorize request
106
+ interface BcAuthorizeRequest {
107
+ login_hint: string; // e.g. "ID:46733123454/MSISDN"
108
+ scope: string; // e.g. "profile"
109
+ access_type: "online" | "offline";
110
+ consent_valid_in?: number; // Consent validity in seconds
111
+ client_notification_token?: string; // Token for notifications
112
+ scope_instruction?: string; // Custom scope instructions
113
+ }
114
+
115
+ // BC Authorize response
116
+ interface BcAuthorizeResponse {
117
+ auth_req_id: string;
118
+ interval: number;
119
+ expires_in: number;
120
+ }
121
+
122
+ // OAuth2 token request
123
+ interface OAuth2TokenRequest {
124
+ grant_type: string; // e.g. "urn:openid:params:grant-type:ciba"
125
+ auth_req_id: string; // From bcAuthorize response
126
+ }
127
+
128
+ // OAuth2 token response
129
+ interface OAuth2TokenResponse {
130
+ access_token: string;
131
+ token_type: string;
132
+ expires_in: number;
133
+ }
134
+ ```
135
+
136
+ ---
137
+
138
+ ### Sandbox User Provisioning (`Users`)
139
+
140
+ Manage API users for the sandbox environment.
141
+
142
+ ```ts
143
+ const users = momo.Users({ primaryKey: "YOUR_PRIMARY_KEY" });
144
+ ```
145
+
146
+ #### `create(host: string): Promise<string>`
147
+
148
+ Creates a new sandbox API user.
149
+
150
+ - **Arguments**: `host` — Your callback host domain (e.g. `"yourdomain.com"`)
151
+ - **Returns**: The generated user ID (UUID)
152
+ - **Errors**: `ResourceAlreadyExistError` if user exists
153
+
154
+ ```ts
155
+ const userId = await users.create("yourdomain.com");
156
+ ```
157
+
158
+ #### `login(userId: string): Promise<Credentials>`
159
+
160
+ Generates an API key for an existing sandbox user.
161
+
162
+ - **Arguments**: `userId` — The UUID from `create()`
163
+ - **Returns**: `{ apiKey: string }`
164
+ - **Errors**: `ResourceNotFoundError` if user doesn't exist
165
+
166
+ ```ts
167
+ const { apiKey } = await users.login(userId);
168
+ ```
169
+
170
+ #### `getApiUser(referenceId: string): Promise<ApiUserInfo>`
171
+
172
+ Retrieves details of a sandbox API user.
173
+
174
+ - **Arguments**: `referenceId` — The user ID
175
+ - **Returns**: `{ providerCallbackHost: string, targetEnvironment: string }`
176
+ - **Errors**: `ResourceNotFoundError` if user doesn't exist
177
+
178
+ ```ts
179
+ const userInfo = await users.getApiUser(userId);
180
+ ```
181
+
182
+ ---
183
+
62
184
  ### Collections
63
- Manage incoming payments and withdrawals.
64
185
 
65
- #### `requestToPay(request: PaymentRequest)`
66
- Requests a payment from a consumer.
186
+ Manage incoming payments, withdrawals, and account information.
187
+
188
+ ```ts
189
+ const collections = momo.Collections({
190
+ primaryKey: "YOUR_COLLECTIONS_KEY",
191
+ userId: "YOUR_USER_ID",
192
+ userSecret: "YOUR_USER_SECRET",
193
+ });
194
+ ```
195
+
196
+ #### `requestToPay(request: PaymentRequest): Promise<string>`
197
+
198
+ Requests a payment from a consumer (payer).
199
+
67
200
  - **Arguments**:
68
- - `amount`: `string` (e.g., "100.00")
69
- - `currency`: `string` (e.g., "EUR")
70
- - `externalId`: `string` (Optional, for reconciliation)
71
- - `payer`: `{ partyIdType: 'MSISDN' | 'EMAIL' | 'PARTY_CODE', partyId: string }`
72
- - `payerMessage`: `string` (Optional, shown in payer history)
73
- - `payeeNote`: `string` (Optional, shown in your history)
74
- - `callbackUrl`: `string` (Optional, overrides global callback host)
75
201
 
76
- #### `getTransaction(referenceId: string)`
77
- Retrieves status of a payment request. Returns a `Payment` object with `status` (`PENDING`, `SUCCESSFUL`, `FAILED`).
202
+ | Field | Type | Required | Description |
203
+ |-------|------|----------|-------------|
204
+ | `amount` | `string` | ✅ | Amount to collect (e.g. `"500"`) |
205
+ | `currency` | `string` | ✅ | ISO 4217 currency code (e.g. `"EUR"`) |
206
+ | `payer` | `Party` | ✅ | The party being charged |
207
+ | `externalId` | `string` | ❌ | Your internal reference for reconciliation |
208
+ | `payerMessage` | `string` | ❌ | Message shown in payer's transaction history |
209
+ | `payeeNote` | `string` | ❌ | Note shown in your transaction history |
210
+ | `callbackUrl` | `string` | ❌ | Override the global callback URL |
211
+
212
+ - **Returns**: `string` — The reference ID (UUID) for tracking the transaction
213
+ - **Errors**: Validation errors for missing/invalid fields
214
+
215
+ ```ts
216
+ const referenceId = await collections.requestToPay({
217
+ amount: "500",
218
+ currency: "EUR",
219
+ externalId: "order-123",
220
+ payer: { partyIdType: "MSISDN", partyId: "46733123454" },
221
+ payerMessage: "Payment for order #123",
222
+ payeeNote: "Order 123",
223
+ });
224
+ ```
225
+
226
+ #### `getTransaction(referenceId: string): Promise<Payment>`
227
+
228
+ Retrieves the status and details of a payment request.
229
+
230
+ - **Arguments**: `referenceId` — The UUID returned by `requestToPay()`
231
+ - **Returns**:
232
+
233
+ | Field | Type | Description |
234
+ |-------|------|-------------|
235
+ | `financialTransactionId` | `string` | MoMo transaction ID |
236
+ | `externalId` | `string` | Your external reference |
237
+ | `amount` | `string` | Transaction amount |
238
+ | `currency` | `string` | Currency code |
239
+ | `payer` | `Party` | The payer's details |
240
+ | `status` | `"PENDING" \| "SUCCESSFUL" \| "FAILED"` | Payment status |
241
+ | `reason` | `FailureReason` | Failure reason (if `FAILED`) |
242
+
243
+ - **Errors**: Rejects with a typed error if the transaction has `FAILED` status (e.g. `PayerNotFoundError`, `NotEnoughFundsError`)
244
+
245
+ ```ts
246
+ const payment = await collections.getTransaction(referenceId);
247
+ console.log(payment.status); // "SUCCESSFUL"
248
+ ```
249
+
250
+ #### `requestToWithdraw(request: WithdrawalRequest): Promise<string>`
251
+
252
+ Initiates a withdrawal from a payer account (V1).
253
+
254
+ - **Arguments**:
255
+
256
+ | Field | Type | Required | Description |
257
+ |-------|------|----------|-------------|
258
+ | `amount` | `string` | ✅ | Amount to withdraw |
259
+ | `currency` | `string` | ✅ | ISO 4217 currency code |
260
+ | `payee` | `Party` | ✅ | The party receiving the withdrawal |
261
+ | `externalId` | `string` | ❌ | Your internal reference |
262
+ | `payerMessage` | `string` | ❌ | Message for payer |
263
+ | `payeeNote` | `string` | ❌ | Note for payee |
264
+ | `callbackUrl` | `string` | ❌ | Override callback URL |
265
+
266
+ - **Returns**: `string` — The reference ID (UUID)
267
+ - **Errors**: Validation errors for missing/invalid fields
268
+
269
+ #### `requestToWithdrawV2(request: WithdrawalRequest): Promise<string>`
270
+
271
+ Same as `requestToWithdraw` but uses the V2 endpoint.
272
+
273
+ #### `getWithdrawal(referenceId: string): Promise<Withdrawal>`
274
+
275
+ Retrieves the status of a withdrawal request.
276
+
277
+ - **Arguments**: `referenceId` — The UUID from `requestToWithdraw()`
278
+ - **Returns**: Withdrawal details with `status` field
279
+ - **Errors**: Rejects with a typed error if the withdrawal has `FAILED` status
280
+
281
+ #### `sendDeliveryNotification(referenceId: string, notification: DeliveryNotification): Promise<void>`
282
+
283
+ Sends a delivery notification for a completed payment.
284
+
285
+ - **Arguments**:
286
+
287
+ | Field | Type | Required | Description |
288
+ |-------|------|----------|-------------|
289
+ | `referenceId` | `string` | ✅ | The payment reference ID |
290
+ | `notification.notificationMessage` | `string` | ✅ | Notification text (max 160 chars) |
291
+ | `notification.language` | `string` | ❌ | ISO 639-1/639-3 language code |
292
+
293
+ - **Returns**: `void`
294
+
295
+ ```ts
296
+ await collections.sendDeliveryNotification(referenceId, {
297
+ notificationMessage: "Your payment has been received!",
298
+ language: "en",
299
+ });
300
+ ```
301
+
302
+ #### `getBalance(): Promise<Balance>`
303
+
304
+ Returns the account balance.
305
+
306
+ - **Returns**: `{ availableBalance: string, currency: string }`
307
+
308
+ #### `getBalanceInCurrency(currency: string): Promise<Balance>`
309
+
310
+ Returns the account balance in a specific currency.
311
+
312
+ - **Arguments**: `currency` — ISO 4217 currency code (e.g. `"EUR"`)
313
+ - **Returns**: `{ availableBalance: string, currency: string }`
314
+
315
+ #### `isPayerActive(partyId: string, partyIdType?: PartyIdType): Promise<boolean>`
316
+
317
+ Checks if an account holder is active and can receive payments.
318
+
319
+ - **Arguments**: `partyId` — The party identifier, `partyIdType` — defaults to `"MSISDN"`
320
+ - **Returns**: `true` if active, `false` if not found
321
+
322
+ #### `getBasicUserInfo(partyIdType: PartyIdType, partyId: string): Promise<BasicUserInfo>`
323
+
324
+ Retrieves basic user information for an account holder.
325
+
326
+ - **Returns**: `{ given_name, family_name, birthdate, locale, gender }`
327
+
328
+ #### `bcAuthorize(request: BcAuthorizeRequest): Promise<BcAuthorizeResponse>`
329
+
330
+ Initiates a Biometric Consent (BC) authorization flow.
331
+
332
+ - **Arguments**: See `BcAuthorizeRequest` in Common Types above
333
+ - **Returns**: `{ auth_req_id: string, interval: number, expires_in: number }`
334
+
335
+ ```ts
336
+ const authResult = await collections.bcAuthorize({
337
+ login_hint: "ID:46733123454/MSISDN",
338
+ scope: "profile",
339
+ access_type: "online",
340
+ });
341
+ ```
342
+
343
+ #### `getUserInfoWithConsent(): Promise<ConsentKycResponse>`
344
+
345
+ Retrieves user information with KYC consent (requires prior OAuth2 authorization).
346
+
347
+ - **Returns**: User info including `sub`, `name`, `phone_number`, `status`
348
+
349
+ #### `getOAuth2Token(request: OAuth2TokenRequest): Promise<OAuth2TokenResponse>`
78
350
 
79
- #### `getBalance()`
80
- Returns `{ availableBalance: string, currency: string }`.
351
+ Creates an OAuth2 token for consent-based access.
81
352
 
82
- #### `requestToWithdrawV2(request: WithdrawalRequest)`
83
- Initiates a withdrawal from a payer account using V2 specs.
353
+ - **Arguments**: `{ grant_type: string, auth_req_id: string }`
354
+ - **Returns**: `{ access_token: string, token_type: string, expires_in: number }`
355
+
356
+ ```ts
357
+ const token = await collections.getOAuth2Token({
358
+ grant_type: "urn:openid:params:grant-type:ciba",
359
+ auth_req_id: authResult.auth_req_id,
360
+ });
361
+ ```
84
362
 
85
363
  ---
86
364
 
87
365
  ### Disbursements
366
+
88
367
  Manage payouts, deposits, and refunds.
89
368
 
90
- #### `transfer(request: TransferRequest)`
369
+ ```ts
370
+ const disbursements = momo.Disbursements({
371
+ primaryKey: "YOUR_DISBURSEMENTS_KEY",
372
+ userId: "YOUR_USER_ID",
373
+ userSecret: "YOUR_USER_SECRET",
374
+ });
375
+ ```
376
+
377
+ #### `transfer(request: TransferRequest): Promise<string>`
378
+
91
379
  Transfers money from your account to a payee.
380
+
92
381
  - **Arguments**:
93
- - `amount`, `currency`, `externalId`: Same as Collections.
94
- - `payee`: `{ partyIdType: 'MSISDN' | 'EMAIL' | 'PARTY_CODE', partyId: string }`
95
- - `payerMessage`, `payeeNote`, `callbackUrl`: Same as Collections.
96
382
 
97
- #### `depositV2(request: DepositRequest)`
98
- Deposits money into a payee account using V2 specs.
383
+ | Field | Type | Required | Description |
384
+ |-------|------|----------|-------------|
385
+ | `amount` | `string` | ✅ | Amount to transfer |
386
+ | `currency` | `string` | ✅ | ISO 4217 currency code |
387
+ | `payee` | `Party` | ✅ | The party receiving the transfer |
388
+ | `externalId` | `string` | ❌ | Your internal reference |
389
+ | `payerMessage` | `string` | ❌ | Message for payer |
390
+ | `payeeNote` | `string` | ❌ | Note for payee |
391
+ | `callbackUrl` | `string` | ❌ | Override callback URL |
392
+
393
+ - **Returns**: `string` — The reference ID (UUID)
394
+
395
+ ```ts
396
+ const referenceId = await disbursements.transfer({
397
+ amount: "250",
398
+ currency: "EUR",
399
+ externalId: "payout-456",
400
+ payee: { partyIdType: "MSISDN", partyId: "46733123454" },
401
+ payerMessage: "Salary payment",
402
+ payeeNote: "March salary",
403
+ });
404
+ ```
405
+
406
+ #### `getTransaction(referenceId: string): Promise<Transfer>`
407
+
408
+ Retrieves the status and details of a transfer.
409
+
410
+ - **Returns**: Transfer details with `status` (`PENDING`, `SUCCESSFUL`, `FAILED`)
411
+ - **Errors**: Rejects with a typed error if the transfer has `FAILED` status
412
+
413
+ #### `deposit(request: DepositRequest): Promise<string>`
414
+
415
+ Deposits money into a payee account (V1).
416
+
417
+ - **Arguments**:
418
+
419
+ | Field | Type | Required | Description |
420
+ |-------|------|----------|-------------|
421
+ | `amount` | `string` | ✅ | Amount to deposit |
422
+ | `currency` | `string` | ✅ | ISO 4217 currency code |
423
+ | `payee` | `Party` | ✅ | The party receiving the deposit |
424
+ | `externalId` | `string` | ❌ | Your internal reference |
425
+ | `payerMessage` | `string` | ❌ | Message for payer |
426
+ | `payeeNote` | `string` | ❌ | Note for payee |
427
+ | `callbackUrl` | `string` | ❌ | Override callback URL |
428
+
429
+ - **Returns**: `string` — The reference ID (UUID)
430
+
431
+ #### `depositV2(request: DepositRequest): Promise<string>`
432
+
433
+ Same as `deposit` but uses the V2 endpoint.
434
+
435
+ #### `getDeposit(referenceId: string): Promise<Deposit>`
436
+
437
+ Retrieves the status of a deposit.
438
+
439
+ - **Errors**: Rejects with a typed error if the deposit has `FAILED` status
440
+
441
+ #### `refund(request: RefundRequest): Promise<string>`
442
+
443
+ Refunds a previous transaction (V1).
99
444
 
100
- #### `refundV2(request: RefundRequest)`
101
- Refunds a previous transaction.
102
445
  - **Arguments**:
103
- - `amount`, `currency`, `externalId`, `payerMessage`, `payeeNote`
104
- - `referenceIdToRefund`: `string` (The original transaction ID)
446
+
447
+ | Field | Type | Required | Description |
448
+ |-------|------|----------|-------------|
449
+ | `referenceIdToRefund` | `string` | ✅ | UUID of the original transaction to refund |
450
+ | `amount` | `string` | ✅ | Amount to refund |
451
+ | `currency` | `string` | ✅ | ISO 4217 currency code |
452
+ | `externalId` | `string` | ❌ | Your internal reference |
453
+ | `payerMessage` | `string` | ❌ | Message for payer |
454
+ | `payeeNote` | `string` | ❌ | Note for payee |
455
+ | `callbackUrl` | `string` | ❌ | Override callback URL |
456
+
457
+ - **Returns**: `string` — The refund reference ID (UUID)
458
+
459
+ ```ts
460
+ const refundId = await disbursements.refund({
461
+ referenceIdToRefund: originalTransactionId,
462
+ amount: "50",
463
+ currency: "EUR",
464
+ externalId: "refund-789",
465
+ payerMessage: "Refund for damaged goods",
466
+ payeeNote: "Partial refund",
467
+ });
468
+ ```
469
+
470
+ #### `refundV2(request: RefundRequest): Promise<string>`
471
+
472
+ Same as `refund` but uses the V2 endpoint.
473
+
474
+ #### `getRefund(referenceId: string): Promise<Refund>`
475
+
476
+ Retrieves the status of a refund.
477
+
478
+ - **Errors**: Rejects with a typed error if the refund has `FAILED` status
479
+
480
+ #### `getBalance(): Promise<Balance>`
481
+
482
+ Returns the account balance.
483
+
484
+ #### `getBalanceInCurrency(currency: string): Promise<Balance>`
485
+
486
+ Returns the account balance in a specific currency.
487
+
488
+ #### `isPayerActive(partyId: string, partyIdType?: PartyIdType): Promise<boolean>`
489
+
490
+ Checks if an account holder is active.
491
+
492
+ #### `getBasicUserInfo(partyIdType: PartyIdType, partyId: string): Promise<BasicUserInfo>`
493
+
494
+ Retrieves basic user information for an account holder.
495
+
496
+ #### `bcAuthorize(request: BcAuthorizeRequest): Promise<BcAuthorizeResponse>`
497
+
498
+ Initiates a BC authorization flow. Uses **Basic Auth** for this endpoint.
499
+
500
+ #### `getUserInfoWithConsent(): Promise<ConsentKycResponse>`
501
+
502
+ Retrieves user info with KYC consent (requires prior OAuth2 authorization).
503
+
504
+ #### `getOAuth2Token(request: OAuth2TokenRequest): Promise<OAuth2TokenResponse>`
505
+
506
+ Creates an OAuth2 token for consent-based access.
105
507
 
106
508
  ---
107
509
 
108
510
  ### Remittance
109
- Manage cross-border transfers.
110
511
 
111
- #### `transfer(request: CashTransferRequest)`
112
- - **Additional Arguments**:
113
- - `originatingCountry`: `string` (ISO code)
114
- - `originalAmount`: `string`
115
- - `originalCurrency`: `string`
512
+ Manage cross-border money transfers.
513
+
514
+ ```ts
515
+ const remittance = momo.Remittance({
516
+ primaryKey: "YOUR_REMITTANCE_KEY",
517
+ userId: "YOUR_USER_ID",
518
+ userSecret: "YOUR_USER_SECRET",
519
+ });
520
+ ```
521
+
522
+ #### `transfer(request: CashTransferRequest): Promise<string>`
523
+
524
+ Sends money cross-border to a beneficiary (V1).
525
+
526
+ - **Arguments**:
527
+
528
+ | Field | Type | Required | Description |
529
+ |-------|------|----------|-------------|
530
+ | `amount` | `string` | ✅ | Amount to transfer |
531
+ | `currency` | `string` | ✅ | ISO 4217 currency code |
532
+ | `payee` | `Party` | ✅ | The beneficiary |
533
+ | `externalId` | `string` | ❌ | Your internal reference |
534
+ | `originatingCountry` | `string` | ❌ | ISO country code of sender |
535
+ | `originalAmount` | `string` | ❌ | Original amount before conversion |
536
+ | `originalCurrency` | `string` | ❌ | Original currency before conversion |
537
+ | `payerMessage` | `string` | ❌ | Message for payer |
538
+ | `payeeNote` | `string` | ❌ | Note for payee |
539
+ | `callbackUrl` | `string` | ❌ | Override callback URL |
540
+
541
+ - **Returns**: `string` — The reference ID (UUID)
542
+
543
+ ```ts
544
+ const referenceId = await remittance.transfer({
545
+ amount: "150",
546
+ currency: "EUR",
547
+ externalId: "remit-001",
548
+ payee: { partyIdType: "MSISDN", partyId: "46733123454" },
549
+ payerMessage: "Family support",
550
+ payeeNote: "Monthly remittance",
551
+ });
552
+ ```
553
+
554
+ #### `getTransaction(referenceId: string): Promise<CashTransfer>`
555
+
556
+ Retrieves the status and details of a transfer.
557
+
558
+ - **Returns**: Transfer details with `status` (`PENDING`, `SUCCESSFUL`, `FAILED`)
559
+ - **Errors**: Rejects with a typed error if the transfer has `FAILED` status
560
+
561
+ #### `cashTransfer(request: CashTransferRequest): Promise<string>`
562
+
563
+ Sends a cross-border cash transfer using the **V2** endpoint.
564
+
565
+ - **Arguments**: Same as `transfer()` above
566
+ - **Returns**: `string` — The reference ID (UUID)
567
+
568
+ ```ts
569
+ const refId = await remittance.cashTransfer({
570
+ amount: "75",
571
+ currency: "EUR",
572
+ payee: { partyIdType: "MSISDN", partyId: "46733123454" },
573
+ });
574
+ ```
575
+
576
+ #### `getCashTransfer(referenceId: string): Promise<CashTransfer>`
577
+
578
+ Retrieves the status of a V2 cash transfer.
579
+
580
+ - **Errors**: Rejects with a typed error if the transfer has `FAILED` status
581
+
582
+ #### `getBalance(): Promise<Balance>`
583
+
584
+ Returns the account balance.
585
+
586
+ #### `getBalanceInCurrency(currency: string): Promise<Balance>`
587
+
588
+ Returns the account balance in a specific currency.
589
+
590
+ #### `isPayerActive(partyId: string, partyIdType?: PartyIdType): Promise<boolean>`
591
+
592
+ Checks if a beneficiary is active and can receive transfers.
593
+
594
+ #### `getBasicUserInfo(partyId: string): Promise<BasicUserInfo>`
595
+
596
+ Retrieves basic user information. Remittance uses `MSISDN` by default.
597
+
598
+ #### `bcAuthorize(request: BcAuthorizeRequest): Promise<BcAuthorizeResponse>`
599
+
600
+ Initiates a BC authorization flow. Uses **Basic Auth** for this endpoint.
601
+
602
+ #### `getUserInfoWithConsent(): Promise<ConsentKycResponse>`
603
+
604
+ Retrieves user info with KYC consent (requires prior OAuth2 authorization).
605
+
606
+ #### `getOAuth2Token(request: OAuth2TokenRequest): Promise<OAuth2TokenResponse>`
607
+
608
+ Creates an OAuth2 token for consent-based access.
609
+
610
+ ---
611
+
612
+ ## Error Handling
613
+
614
+ All API errors are mapped to typed error classes that extend `MtnMoMoError`. You can catch specific errors:
615
+
616
+ ```ts
617
+ import { PayerNotFoundError, NotEnoughFundsError } from "@maxkabechani/mtn-momo-sdk";
618
+
619
+ try {
620
+ await collections.requestToPay({ ... });
621
+ } catch (error) {
622
+ if (error instanceof PayerNotFoundError) {
623
+ console.error("The payer MSISDN was not found");
624
+ } else if (error instanceof NotEnoughFundsError) {
625
+ console.error("Insufficient funds");
626
+ }
627
+ }
628
+ ```
629
+
630
+ ### Error Types
631
+
632
+ | Error Class | When It Occurs |
633
+ |-------------|---------------|
634
+ | `ApprovalRejectedError` | The user rejected the payment approval |
635
+ | `ExpiredError` | The transaction has expired |
636
+ | `InternalProcessingError` | An internal error occurred on the MoMo platform |
637
+ | `InvalidCallbackUrlHostError` | The callback URL host is invalid |
638
+ | `InvalidCurrencyError` | The specified currency is not supported |
639
+ | `NotAllowedTargetEnvironmentError` | Operation not allowed in the target environment |
640
+ | `NotAllowedError` | The operation is not allowed |
641
+ | `NotEnoughFundsError` | The payer has insufficient funds |
642
+ | `PayeeNotFoundError` | The payee account was not found |
643
+ | `PayeeNotAllowedToReceiveError` | The payee is not allowed to receive funds |
644
+ | `PayerLimitReachedError` | The payer has reached their transaction limit |
645
+ | `PayerNotFoundError` | The payer account was not found |
646
+ | `PaymentNotApprovedError` | The payment was not approved |
647
+ | `ResourceAlreadyExistError` | The resource already exists (e.g. duplicate transaction) |
648
+ | `ResourceNotFoundError` | The requested resource was not found |
649
+ | `ServiceUnavailableError` | The service is temporarily unavailable |
650
+ | `TransactionCancelledError` | The transaction was cancelled |
651
+ | `UnspecifiedError` | An unspecified error occurred |
116
652
 
117
653
  ---
118
654
 
119
655
  ## Going Live (Production)
120
656
 
121
- Transitioning from Sandbox to Production requires a few changes:
657
+ 1. **Change the environment**:
122
658
 
123
- 1. **Environment Flag**:
124
- Change `Environment.SANDBOX` to `Environment.PRODUCTION`.
125
659
  ```ts
126
660
  const momo = create({
127
661
  callbackHost: "production-api.yoursite.com",
@@ -129,18 +663,15 @@ Transitioning from Sandbox to Production requires a few changes:
129
663
  });
130
664
  ```
131
665
 
132
- 2. **Production Credentials**:
133
- - Get your **Primary Key** from the [MTN MoMo Developer Portal](https://momodeveloper.mtn.com/).
134
- - Obtain your production **User ID** and **User Secret** through the official onboarding process in your specific region.
666
+ 2. **Use production credentials** from the [MTN MoMo Developer Portal](https://momodeveloper.mtn.com/).
135
667
 
136
- 3. **Endpoints**:
137
- The SDK handles the URL switch automatically when `Environment.PRODUCTION` is set.
668
+ 3. **Endpoints**: The SDK handles the URL switch automatically.
138
669
 
139
670
  ---
140
671
 
141
672
  ## Environment Variables
142
673
 
143
- For security, it is highly recommended to store your credentials in environment variables (e.g., using `dotenv`):
674
+ Store credentials securely using environment variables:
144
675
 
145
676
  ```bash
146
677
  # Collections
@@ -159,8 +690,6 @@ REMITTANCE_USER_ID=your_id
159
690
  REMITTANCE_USER_SECRET=your_secret
160
691
  ```
161
692
 
162
- Usage in your application:
163
-
164
693
  ```ts
165
694
  import "dotenv/config";
166
695
 
@@ -175,13 +704,14 @@ const collections = momo.Collections({
175
704
 
176
705
  ## Development & Testing
177
706
 
178
- We use [Bun](https://bun.sh) for efficient development.
179
-
180
707
  ```bash
181
708
  bun install
182
- bun run test # Run unit tests
183
- bun run build # Build for production (ESM/CJS)
709
+ bun run test # Run all tests (unit + integration)
710
+ bun run test:coverage # Run tests with coverage
711
+ bun run typecheck # Type check
712
+ bun run build # Build for production (ESM + CJS)
184
713
  ```
185
714
 
186
715
  ## License
716
+
187
717
  ISC