monime-package 1.0.4 → 1.0.6
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/README.md +811 -89
- package/dist/index.d.mts +783 -88
- package/dist/index.d.ts +783 -88
- package/dist/index.js +483 -75
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +475 -67
- package/dist/index.mjs.map +1 -1
- package/package.json +39 -37
package/README.md
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
|
|
2
2
|
# monime-package
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
Official, lightweight TypeScript SDK for Monime. It provides a typed client for common Monime endpoints with consistent results and simple ergonomics.
|
|
5
5
|
|
|
6
|
-

|
|
7
|
+

|
|
8
|
+

|
|
7
9
|

|
|
8
10
|

|
|
9
11
|
|
|
@@ -13,27 +15,41 @@ Package: `monime-package`
|
|
|
13
15
|
|
|
14
16
|
## Table of Contents
|
|
15
17
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
18
|
+
- **[Features](#features)**
|
|
19
|
+
- **[Installation](#installation)**
|
|
20
|
+
- **[Environment Variables](#environment-variables)**
|
|
21
|
+
- **[Quick Start](#quick-start)**
|
|
22
|
+
- **[API Reference](#api-reference)**
|
|
23
|
+
- **[Financial Accounts](#financial-accounts)**
|
|
24
|
+
- **[Internal Transfers](#internal-transfers)**
|
|
25
|
+
- **[Payment Codes](#payment-codes)**
|
|
26
|
+
- **[Payouts](#payouts)**
|
|
27
|
+
- **[Financial Transactions](#financial-transactions)**
|
|
28
|
+
- **[Checkout Sessions](#checkout-sessions)**
|
|
29
|
+
- **[Configuration](#configuration)**
|
|
30
|
+
- **[Complete Examples](#complete-examples)**
|
|
31
|
+
- **[TypeScript Types](#typescript-types)**
|
|
32
|
+
- **[Idempotency](#idempotency)**
|
|
33
|
+
- **[Pagination](#pagination)**
|
|
34
|
+
- **[Migration from Old Helpers](#migration-from-old-helpers)**
|
|
35
|
+
- **[Error Handling](#error-handling)**
|
|
36
|
+
- **[Security](#security)**
|
|
37
|
+
- **[Contributing](#contributing)**
|
|
38
|
+
- **[Support](#support)**
|
|
39
|
+
- **[License](#license)**
|
|
27
40
|
|
|
28
41
|
---
|
|
29
42
|
|
|
30
43
|
## Features
|
|
31
44
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
45
|
+
- **Typed** request/response objects for safer integrations
|
|
46
|
+
- **Predictable** return shape: `{ success, data?, error? }`
|
|
47
|
+
- **Client-based** auth: set credentials once per instance
|
|
48
|
+
- **Minimal deps** (`axios`) and small surface area
|
|
49
|
+
- **Full API coverage** for all Monime endpoints
|
|
50
|
+
- **Mobile Money support** (Africell, Orange, etc.)
|
|
51
|
+
- **Bank transfers** and digital wallet integrations
|
|
52
|
+
- **Checkout sessions** for hosted payment pages
|
|
37
53
|
|
|
38
54
|
---
|
|
39
55
|
|
|
@@ -65,170 +81,876 @@ You can also pass credentials directly when creating the client.
|
|
|
65
81
|
### Create a client
|
|
66
82
|
|
|
67
83
|
```ts
|
|
68
|
-
import { createClient } from
|
|
84
|
+
import { createClient } from "monime-package";
|
|
69
85
|
|
|
70
86
|
const client = createClient({
|
|
71
|
-
|
|
87
|
+
monimeSpaceId: process.env.MONIME_SPACE_ID!,
|
|
72
88
|
accessToken: process.env.MONIME_ACCESS_TOKEN!,
|
|
73
|
-
})
|
|
89
|
+
});
|
|
74
90
|
```
|
|
75
91
|
|
|
76
|
-
Now all methods
|
|
92
|
+
Now all methods use the client’s credentials automatically.
|
|
93
|
+
|
|
94
|
+
### Import styles
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
// ESM / TypeScript
|
|
98
|
+
import { createClient, type DestinationOption } from "monime-package";
|
|
99
|
+
|
|
100
|
+
// CommonJS
|
|
101
|
+
// const { createClient } = require("monime-package");
|
|
102
|
+
```
|
|
77
103
|
|
|
78
104
|
---
|
|
79
105
|
|
|
80
|
-
##
|
|
106
|
+
## API Reference
|
|
81
107
|
|
|
82
|
-
All methods return:
|
|
108
|
+
All methods return the same envelope:
|
|
83
109
|
|
|
84
110
|
```ts
|
|
85
111
|
type Result<T> = {
|
|
86
|
-
success: boolean
|
|
87
|
-
data?: T
|
|
88
|
-
error?: Error
|
|
89
|
-
}
|
|
112
|
+
success: boolean;
|
|
113
|
+
data?: T;
|
|
114
|
+
error?: Error;
|
|
115
|
+
};
|
|
90
116
|
```
|
|
91
117
|
|
|
118
|
+
The client exposes namespaced APIs under `client.<module>`. Below is the complete API reference:
|
|
119
|
+
|
|
92
120
|
### Financial Accounts
|
|
93
121
|
|
|
122
|
+
Manage digital wallets and financial accounts.
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
// Create a new financial account
|
|
126
|
+
client.financialAccount.create(name: string): Promise<Result<CreateFinancialAccount>>
|
|
127
|
+
|
|
128
|
+
// Get account details by ID
|
|
129
|
+
client.financialAccount.get(financialAccountId: string): Promise<Result<GetFinancialAccount>>
|
|
130
|
+
|
|
131
|
+
// List all financial accounts
|
|
132
|
+
client.financialAccount.getAll(): Promise<Result<AllFinancialAccount>>
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
**Parameters:**
|
|
136
|
+
- `name`: Account name (required)
|
|
137
|
+
- `financialAccountId`: Unique account identifier (required)
|
|
138
|
+
|
|
139
|
+
**Example:**
|
|
94
140
|
```ts
|
|
95
|
-
|
|
96
|
-
client.
|
|
141
|
+
// Create account
|
|
142
|
+
const account = await client.financialAccount.create("My Wallet");
|
|
143
|
+
if (account.success) {
|
|
144
|
+
console.log("Account ID:", account.data.result.id);
|
|
145
|
+
console.log("Balance:", account.data.result.balance.available.value);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Get account details
|
|
149
|
+
const details = await client.financialAccount.get("fa-123456");
|
|
97
150
|
```
|
|
98
151
|
|
|
99
152
|
### Internal Transfers
|
|
100
153
|
|
|
154
|
+
Transfer funds between your financial accounts.
|
|
155
|
+
|
|
101
156
|
```ts
|
|
102
|
-
|
|
157
|
+
// Create internal transfer
|
|
158
|
+
client.internalTransfer.create(
|
|
103
159
|
sourceAccount: string,
|
|
104
160
|
destinationAccount: string,
|
|
105
|
-
amount: number
|
|
161
|
+
amount: number,
|
|
106
162
|
): Promise<Result<CreateInternalTransfer>>
|
|
163
|
+
|
|
164
|
+
// Get transfer details
|
|
165
|
+
client.internalTransfer.get(internalTransferId: string): Promise<Result<InternalTransfer>>
|
|
166
|
+
|
|
167
|
+
// List all transfers
|
|
168
|
+
client.internalTransfer.getAll(): Promise<Result<AllInternalTransfers>>
|
|
169
|
+
|
|
170
|
+
// Cancel/delete a transfer
|
|
171
|
+
client.internalTransfer.delete(internalTransferId: string): Promise<{ success: boolean; error?: Error }>
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
**Parameters:**
|
|
175
|
+
- `sourceAccount`: Source financial account ID (required)
|
|
176
|
+
- `destinationAccount`: Destination financial account ID (required)
|
|
177
|
+
- `amount`: Transfer amount in SLE (required, must be > 0)
|
|
178
|
+
- `internalTransferId`: Transfer ID for get/delete operations (required)
|
|
179
|
+
|
|
180
|
+
**Example:**
|
|
181
|
+
```ts
|
|
182
|
+
// Transfer 1000 SLE between accounts
|
|
183
|
+
const transfer = await client.internalTransfer.create("fa-source", "fa-dest", 1000);
|
|
184
|
+
if (transfer.success) {
|
|
185
|
+
console.log("Transfer ID:", transfer.data.result.id);
|
|
186
|
+
console.log("Status:", transfer.data.result.status);
|
|
187
|
+
}
|
|
107
188
|
```
|
|
108
189
|
|
|
109
190
|
### Payment Codes
|
|
110
191
|
|
|
192
|
+
Generate USSD payment codes for mobile money transactions.
|
|
193
|
+
|
|
111
194
|
```ts
|
|
112
|
-
|
|
195
|
+
// Create payment code
|
|
196
|
+
client.paymentCode.create(
|
|
113
197
|
paymentName: string,
|
|
114
198
|
amount: number,
|
|
115
199
|
financialAccount: string,
|
|
116
200
|
username: string,
|
|
117
|
-
phoneNumber: string
|
|
201
|
+
phoneNumber: string,
|
|
118
202
|
): Promise<Result<CreatePaymentCode>>
|
|
119
203
|
|
|
120
|
-
|
|
204
|
+
// Get payment code details
|
|
205
|
+
client.paymentCode.get(paymentCodeId: string): Promise<Result<GetOne>>
|
|
206
|
+
|
|
207
|
+
// List all payment codes
|
|
208
|
+
client.paymentCode.getAll(): Promise<Result<GetAllPaymentCode>>
|
|
209
|
+
|
|
210
|
+
// Delete payment code
|
|
211
|
+
client.paymentCode.delete(paymentCodeId: string): Promise<{ success: boolean; error?: Error }>
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
**Parameters:**
|
|
215
|
+
- `paymentName`: Description for the payment (required)
|
|
216
|
+
- `amount`: Payment amount in SLE (required, must be > 0)
|
|
217
|
+
- `financialAccount`: Target financial account ID (required)
|
|
218
|
+
- `username`: Customer name (required)
|
|
219
|
+
- `phoneNumber`: Authorized phone number (required)
|
|
220
|
+
- `paymentCodeId`: Payment code ID for get/delete operations (required)
|
|
221
|
+
|
|
222
|
+
**Example:**
|
|
223
|
+
```ts
|
|
224
|
+
// Create USSD payment code
|
|
225
|
+
const paymentCode = await client.paymentCode.create(
|
|
226
|
+
"Order #12345",
|
|
227
|
+
5000, // 50.00 SLE
|
|
228
|
+
"fa-123456",
|
|
229
|
+
"John Doe",
|
|
230
|
+
"0771234567"
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
if (paymentCode.success) {
|
|
234
|
+
console.log("USSD Code:", paymentCode.data.result.ussdCode);
|
|
235
|
+
console.log("Expires at:", paymentCode.data.result.expireTime);
|
|
236
|
+
}
|
|
121
237
|
```
|
|
122
238
|
|
|
123
239
|
### Payouts
|
|
124
240
|
|
|
241
|
+
Send money to mobile money providers, banks, or wallets.
|
|
242
|
+
|
|
125
243
|
```ts
|
|
126
|
-
|
|
244
|
+
// Create payout
|
|
245
|
+
client.payout.create(
|
|
127
246
|
amount: number,
|
|
128
|
-
|
|
129
|
-
sourceAccount: string
|
|
247
|
+
destination: DestinationOption,
|
|
248
|
+
sourceAccount: string,
|
|
130
249
|
): Promise<Result<CreatePayout>>
|
|
250
|
+
|
|
251
|
+
// List all payouts
|
|
252
|
+
client.payout.get(): Promise<Result<GetAll>>
|
|
253
|
+
|
|
254
|
+
// Get specific payout
|
|
255
|
+
client.payout.getOne(payoutId: string): Promise<Result<GetOnePayout>>
|
|
256
|
+
|
|
257
|
+
// Cancel payout
|
|
258
|
+
client.payout.delete(payoutId: string): Promise<{ success: boolean; error?: Error }>
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
**Destination Types:**
|
|
262
|
+
```ts
|
|
263
|
+
type DestinationOption =
|
|
264
|
+
| { type: "momo"; providerId: "m17" | "m18"; phoneNumber: string }
|
|
265
|
+
| { type: "bank"; providerId: "b01" | "b02" | "b03"; accountNumber: string }
|
|
266
|
+
| { type: "wallet"; providerId: "w01" | "w02"; walletId: string };
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
**Parameters:**
|
|
270
|
+
- `amount`: Payout amount in SLE (required, must be > 0)
|
|
271
|
+
- `destination`: Payout destination (required)
|
|
272
|
+
- `sourceAccount`: Source financial account ID (required)
|
|
273
|
+
- `payoutId`: Payout ID for get/delete operations (required)
|
|
274
|
+
|
|
275
|
+
**Example:**
|
|
276
|
+
```ts
|
|
277
|
+
// Mobile money payout
|
|
278
|
+
const mobileMoneyPayout = await client.payout.create(
|
|
279
|
+
10000, // 100.00 SLE
|
|
280
|
+
{ type: "momo", providerId: "m17", phoneNumber: "0771234567" },
|
|
281
|
+
"fa-123456"
|
|
282
|
+
);
|
|
283
|
+
|
|
284
|
+
// Bank transfer payout
|
|
285
|
+
const bankPayout = await client.payout.create(
|
|
286
|
+
50000, // 500.00 SLE
|
|
287
|
+
{ type: "bank", providerId: "b01", accountNumber: "1234567890" },
|
|
288
|
+
"fa-123456"
|
|
289
|
+
);
|
|
131
290
|
```
|
|
132
291
|
|
|
133
|
-
|
|
292
|
+
### Financial Transactions
|
|
293
|
+
|
|
294
|
+
Query transaction history and details.
|
|
295
|
+
|
|
296
|
+
```ts
|
|
297
|
+
// Get transaction details
|
|
298
|
+
client.financialTransaction.get(transactionId: string): Promise<Result<GetTransaction>>
|
|
299
|
+
|
|
300
|
+
// List all transactions
|
|
301
|
+
client.financialTransaction.getAll(): Promise<Result<AllTransaction>>
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
**Parameters:**
|
|
305
|
+
- `transactionId`: Transaction ID (required)
|
|
306
|
+
|
|
307
|
+
**Example:**
|
|
308
|
+
```ts
|
|
309
|
+
// Get all transactions
|
|
310
|
+
const transactions = await client.financialTransaction.getAll();
|
|
311
|
+
if (transactions.success) {
|
|
312
|
+
transactions.data.result.forEach(tx => {
|
|
313
|
+
console.log(`${tx.type}: ${tx.amount.value} ${tx.amount.currency}`);
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
### Checkout Sessions
|
|
319
|
+
|
|
320
|
+
Create hosted payment pages for seamless customer payments.
|
|
321
|
+
|
|
322
|
+
```ts
|
|
323
|
+
// Create checkout session
|
|
324
|
+
client.checkoutSession.create(
|
|
325
|
+
name: string,
|
|
326
|
+
amount: number,
|
|
327
|
+
quantity: number,
|
|
328
|
+
successUrl: string,
|
|
329
|
+
cancelUrl: string,
|
|
330
|
+
description?: string,
|
|
331
|
+
financialAccountId?: string,
|
|
332
|
+
primaryColor?: string,
|
|
333
|
+
images?: string[],
|
|
334
|
+
): Promise<Result<CreateCheckout>>
|
|
335
|
+
|
|
336
|
+
// List all checkout sessions
|
|
337
|
+
client.checkoutSession.get(): Promise<Result<AllCheckout>>
|
|
338
|
+
|
|
339
|
+
// Get specific checkout session
|
|
340
|
+
client.checkoutSession.getOne(checkoutId: string): Promise<Result<OneCheckout>>
|
|
341
|
+
|
|
342
|
+
// Delete checkout session
|
|
343
|
+
client.checkoutSession.delete(checkoutId: string): Promise<{ success: boolean; error?: Error }>
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
**Parameters:**
|
|
347
|
+
- `name`: Product/service name (required)
|
|
348
|
+
- `amount`: Price per item in SLE (required)
|
|
349
|
+
- `quantity`: Number of items (required)
|
|
350
|
+
- `successUrl`: Redirect URL after successful payment (required)
|
|
351
|
+
- `cancelUrl`: Redirect URL when payment is cancelled (required)
|
|
352
|
+
- `description`: Product description (optional)
|
|
353
|
+
- `financialAccountId`: Target account for payments (optional)
|
|
354
|
+
- `primaryColor`: Brand color in hex format (optional)
|
|
355
|
+
- `images`: Product image URLs (optional)
|
|
356
|
+
- `checkoutId`: Checkout session ID for get/delete operations (required)
|
|
357
|
+
|
|
358
|
+
**Example:**
|
|
359
|
+
```ts
|
|
360
|
+
// Create checkout for e-commerce
|
|
361
|
+
const checkout = await client.checkoutSession.create(
|
|
362
|
+
"Premium Subscription",
|
|
363
|
+
2500, // 25.00 SLE per month
|
|
364
|
+
1,
|
|
365
|
+
"https://myapp.com/success",
|
|
366
|
+
"https://myapp.com/cancel",
|
|
367
|
+
"Monthly premium subscription",
|
|
368
|
+
"fa-123456",
|
|
369
|
+
"#3B82F6", // Blue color
|
|
370
|
+
["https://myapp.com/images/premium.jpg"]
|
|
371
|
+
);
|
|
372
|
+
|
|
373
|
+
if (checkout.success) {
|
|
374
|
+
// Redirect customer to checkout page
|
|
375
|
+
console.log("Checkout URL:", checkout.data.result.redirectUrl);
|
|
376
|
+
console.log("Order Number:", checkout.data.result.orderNumber);
|
|
377
|
+
}
|
|
378
|
+
```
|
|
134
379
|
|
|
135
380
|
---
|
|
136
381
|
|
|
137
|
-
##
|
|
382
|
+
## Configuration
|
|
138
383
|
|
|
139
|
-
|
|
384
|
+
The client accepts the following options (see `src/client.ts`):
|
|
140
385
|
|
|
141
386
|
```ts
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
387
|
+
type ClientOptions = {
|
|
388
|
+
monimeSpaceId: string; // Your Monime Space ID
|
|
389
|
+
accessToken: string; // Your Monime API token
|
|
390
|
+
};
|
|
145
391
|
```
|
|
146
392
|
|
|
147
|
-
|
|
393
|
+
- **Authentication**: Both values are required. Prefer environment variables.
|
|
394
|
+
- **Headers**: SDK automatically sets `Authorization` and `Monime-Space-Id` for each call.
|
|
395
|
+
|
|
396
|
+
---
|
|
397
|
+
|
|
398
|
+
## Complete Examples
|
|
399
|
+
|
|
400
|
+
Here are comprehensive examples showing real-world usage patterns:
|
|
401
|
+
|
|
402
|
+
### Complete E-commerce Integration
|
|
148
403
|
|
|
149
404
|
```ts
|
|
150
|
-
|
|
151
|
-
|
|
405
|
+
import { createClient, type DestinationOption } from "monime-package";
|
|
406
|
+
|
|
407
|
+
// Initialize client
|
|
408
|
+
const client = createClient({
|
|
409
|
+
monimeSpaceId: process.env.MONIME_SPACE_ID!,
|
|
410
|
+
accessToken: process.env.MONIME_ACCESS_TOKEN!,
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
// Create business account
|
|
414
|
+
const businessAccount = await client.financialAccount.create("E-commerce Store");
|
|
415
|
+
if (!businessAccount.success) {
|
|
416
|
+
throw new Error(`Failed to create account: ${businessAccount.error?.message}`);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
const accountId = businessAccount.data!.result.id;
|
|
420
|
+
console.log(`Created account: ${accountId}`);
|
|
421
|
+
console.log(`Balance: ${businessAccount.data!.result.balance.available.value} SLE`);
|
|
422
|
+
|
|
423
|
+
// Create checkout session for customer
|
|
424
|
+
const checkout = await client.checkoutSession.create(
|
|
425
|
+
"Digital Camera",
|
|
426
|
+
45000, // 450.00 SLE
|
|
427
|
+
1,
|
|
428
|
+
"https://store.com/success",
|
|
429
|
+
"https://store.com/cancel",
|
|
430
|
+
"Professional DSLR Camera with lens kit",
|
|
431
|
+
accountId,
|
|
432
|
+
"#2563EB", // Brand blue
|
|
433
|
+
["https://store.com/camera.jpg"]
|
|
434
|
+
);
|
|
435
|
+
|
|
436
|
+
if (checkout.success) {
|
|
437
|
+
console.log(`Checkout created: ${checkout.data!.result.id}`);
|
|
438
|
+
console.log(`Payment URL: ${checkout.data!.result.redirectUrl}`);
|
|
439
|
+
console.log(`Order: ${checkout.data!.result.orderNumber}`);
|
|
440
|
+
}
|
|
152
441
|
```
|
|
153
442
|
|
|
154
|
-
###
|
|
443
|
+
### Payment Processing Workflow
|
|
155
444
|
|
|
156
445
|
```ts
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
446
|
+
// 1. Generate USSD payment code for customer
|
|
447
|
+
const paymentCode = await client.paymentCode.create(
|
|
448
|
+
"Invoice #INV-2024-001",
|
|
449
|
+
15000, // 150.00 SLE
|
|
450
|
+
accountId,
|
|
451
|
+
"Customer Name",
|
|
452
|
+
"0771234567"
|
|
453
|
+
);
|
|
454
|
+
|
|
455
|
+
if (paymentCode.success) {
|
|
456
|
+
console.log(`USSD Code: ${paymentCode.data!.result.ussdCode}`);
|
|
457
|
+
console.log(`Expires: ${paymentCode.data!.result.expireTime}`);
|
|
458
|
+
|
|
459
|
+
// Send USSD code to customer via SMS/email
|
|
460
|
+
await sendToCustomer(paymentCode.data!.result.ussdCode);
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
// 2. Monitor payment status
|
|
464
|
+
const checkPaymentStatus = async (codeId: string) => {
|
|
465
|
+
const status = await client.paymentCode.get(codeId);
|
|
466
|
+
if (status.success) {
|
|
467
|
+
console.log(`Payment Status: ${status.data!.result.status}`);
|
|
468
|
+
return status.data!.result.status === 'completed';
|
|
469
|
+
}
|
|
470
|
+
return false;
|
|
471
|
+
};
|
|
472
|
+
|
|
473
|
+
// 3. Process payout to supplier after payment received
|
|
474
|
+
const paySupplier = async () => {
|
|
475
|
+
const payout = await client.payout.create(
|
|
476
|
+
8000, // 80.00 SLE to supplier
|
|
477
|
+
{
|
|
478
|
+
type: "momo",
|
|
479
|
+
providerId: "m17",
|
|
480
|
+
phoneNumber: "0779876543"
|
|
481
|
+
},
|
|
482
|
+
accountId
|
|
483
|
+
);
|
|
484
|
+
|
|
485
|
+
if (payout.success) {
|
|
486
|
+
console.log(`Payout ID: ${payout.data!.result.id}`);
|
|
487
|
+
console.log(`Status: ${payout.data!.result.status}`);
|
|
488
|
+
console.log(`Fees: ${payout.data!.result.fees.map(f => `${f.code}: ${f.amount.value}`)}`);
|
|
489
|
+
}
|
|
490
|
+
};
|
|
160
491
|
```
|
|
161
492
|
|
|
162
|
-
###
|
|
493
|
+
### Multi-Account Management
|
|
163
494
|
|
|
164
495
|
```ts
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
496
|
+
// Create multiple accounts for different purposes
|
|
497
|
+
const accounts = await Promise.all([
|
|
498
|
+
client.financialAccount.create("Sales Revenue"),
|
|
499
|
+
client.financialAccount.create("Operating Expenses"),
|
|
500
|
+
client.financialAccount.create("Tax Reserve"),
|
|
501
|
+
]);
|
|
502
|
+
|
|
503
|
+
// Check if all accounts were created successfully
|
|
504
|
+
if (accounts.every(acc => acc.success)) {
|
|
505
|
+
const [salesAccount, expensesAccount, taxAccount] = accounts.map(acc => acc.data!.result.id);
|
|
506
|
+
|
|
507
|
+
// Distribute revenue: 70% operations, 30% tax reserve
|
|
508
|
+
const revenue = 100000; // 1000.00 SLE
|
|
509
|
+
|
|
510
|
+
const transfers = await Promise.all([
|
|
511
|
+
client.internalTransfer.create(salesAccount, expensesAccount, revenue * 0.7),
|
|
512
|
+
client.internalTransfer.create(salesAccount, taxAccount, revenue * 0.3),
|
|
513
|
+
]);
|
|
514
|
+
|
|
515
|
+
transfers.forEach((transfer, index) => {
|
|
516
|
+
const purpose = index === 0 ? 'operations' : 'tax reserve';
|
|
517
|
+
if (transfer.success) {
|
|
518
|
+
console.log(`${purpose} transfer: ${transfer.data!.result.id}`);
|
|
519
|
+
}
|
|
520
|
+
});
|
|
521
|
+
}
|
|
168
522
|
```
|
|
169
523
|
|
|
170
|
-
###
|
|
524
|
+
### Transaction Monitoring & Reporting
|
|
171
525
|
|
|
172
526
|
```ts
|
|
173
|
-
|
|
174
|
-
|
|
527
|
+
// Get all transactions for reporting
|
|
528
|
+
const transactions = await client.financialTransaction.getAll();
|
|
529
|
+
|
|
530
|
+
if (transactions.success) {
|
|
531
|
+
const txs = transactions.data!.result;
|
|
532
|
+
|
|
533
|
+
// Group transactions by type
|
|
534
|
+
const summary = txs.reduce((acc, tx) => {
|
|
535
|
+
acc[tx.type] = (acc[tx.type] || 0) + tx.amount.value;
|
|
536
|
+
return acc;
|
|
537
|
+
}, {} as Record<string, number>);
|
|
538
|
+
|
|
539
|
+
console.log('Transaction Summary:', summary);
|
|
540
|
+
|
|
541
|
+
// Find large transactions (> 50,000 SLE)
|
|
542
|
+
const largeTransactions = txs.filter(tx => Math.abs(tx.amount.value) > 50000);
|
|
543
|
+
console.log(`Large transactions: ${largeTransactions.length}`);
|
|
544
|
+
|
|
545
|
+
// Check account balances after transactions
|
|
546
|
+
const accountIds = [...new Set(txs.map(tx => tx.financialAccount.id))];
|
|
547
|
+
|
|
548
|
+
for (const accountId of accountIds) {
|
|
549
|
+
const account = await client.financialAccount.get(accountId);
|
|
550
|
+
if (account.success) {
|
|
551
|
+
console.log(`Account ${accountId}: ${account.data!.result.balance.available.value} SLE`);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
}
|
|
175
555
|
```
|
|
176
556
|
|
|
177
|
-
###
|
|
557
|
+
### Error Handling Best Practices
|
|
178
558
|
|
|
179
559
|
```ts
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
560
|
+
// Robust error handling with retries
|
|
561
|
+
const createTransferWithRetry = async (
|
|
562
|
+
sourceAccount: string,
|
|
563
|
+
destinationAccount: string,
|
|
564
|
+
amount: number,
|
|
565
|
+
maxRetries = 3
|
|
566
|
+
) => {
|
|
567
|
+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
568
|
+
const transfer = await client.internalTransfer.create(sourceAccount, destinationAccount, amount);
|
|
569
|
+
|
|
570
|
+
if (transfer.success) {
|
|
571
|
+
return transfer;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
// Log the error
|
|
575
|
+
console.error(`Transfer attempt ${attempt} failed:`, transfer.error?.message);
|
|
576
|
+
|
|
577
|
+
// Don't retry on validation errors
|
|
578
|
+
if (transfer.error?.message?.includes('validation')) {
|
|
579
|
+
throw transfer.error;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
// Wait before retrying (exponential backoff)
|
|
583
|
+
if (attempt < maxRetries) {
|
|
584
|
+
await new Promise(resolve => setTimeout(resolve, Math.pow(2, attempt) * 1000));
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
throw new Error(`Transfer failed after ${maxRetries} attempts`);
|
|
589
|
+
};
|
|
590
|
+
|
|
591
|
+
// Usage
|
|
592
|
+
try {
|
|
593
|
+
const transfer = await createTransferWithRetry("fa-source", "fa-dest", 10000);
|
|
594
|
+
console.log("Transfer successful:", transfer.data!.result.id);
|
|
595
|
+
} catch (error) {
|
|
596
|
+
console.error("Transfer failed permanently:", error.message);
|
|
597
|
+
}
|
|
183
598
|
```
|
|
184
599
|
|
|
185
600
|
---
|
|
186
601
|
|
|
602
|
+
## Idempotency
|
|
603
|
+
|
|
604
|
+
For POST endpoints, the SDK automatically attaches an `Idempotency-Key` header. This helps prevent duplicate requests if you retry the same call. Keys are generated per module instance.
|
|
605
|
+
|
|
606
|
+
---
|
|
607
|
+
|
|
608
|
+
## Pagination
|
|
609
|
+
|
|
610
|
+
List endpoints return a `pagination` object in `data?.pagination` when available, including a `next` cursor/URL. The SDK currently returns this information as-is; use the `next` value to fetch subsequent pages if needed.
|
|
611
|
+
|
|
612
|
+
---
|
|
613
|
+
|
|
187
614
|
## Migration from Old Helpers
|
|
188
615
|
|
|
189
|
-
Previously, you
|
|
616
|
+
Previously, you called standalone helpers and passed credentials on every call:
|
|
190
617
|
|
|
191
618
|
```ts
|
|
192
|
-
|
|
619
|
+
// old (example)
|
|
620
|
+
createFinancialAccount("name", MONIME_SPACE_ID, MONIME_ACCESS_TOKEN);
|
|
193
621
|
```
|
|
194
622
|
|
|
195
|
-
Now,
|
|
623
|
+
Now, instantiate a client once and use namespaced methods. Credentials are stored internally:
|
|
196
624
|
|
|
197
625
|
```ts
|
|
198
|
-
const client = createClient({
|
|
199
|
-
client.
|
|
626
|
+
const client = createClient({ monimeSpaceId, accessToken });
|
|
627
|
+
await client.financialAccount.create("name");
|
|
200
628
|
```
|
|
201
629
|
|
|
202
630
|
---
|
|
203
631
|
|
|
204
|
-
## Folder Structure
|
|
205
632
|
|
|
633
|
+
## Error Handling
|
|
634
|
+
|
|
635
|
+
- **Standard envelope**: every call returns `{ success, data?, error? }`.
|
|
636
|
+
- **Validation**: inputs are validated (e.g. non-empty IDs, positive amounts) and will short-circuit with `success: false` + `Error`.
|
|
637
|
+
- **Axios errors**: when available, `axios` errors are propagated. You can check details with `axios.isAxiosError(error)`.
|
|
638
|
+
|
|
639
|
+
---
|
|
640
|
+
|
|
641
|
+
## Security
|
|
642
|
+
|
|
643
|
+
- Do not commit tokens. Use environment variables or a secret manager.
|
|
644
|
+
- Restrict tokens to the least privileges necessary.
|
|
645
|
+
|
|
646
|
+
---
|
|
647
|
+
|
|
648
|
+
## Versioning
|
|
649
|
+
|
|
650
|
+
This project follows semantic versioning (SemVer). See releases for notable changes.
|
|
651
|
+
|
|
652
|
+
---
|
|
653
|
+
|
|
654
|
+
## Support
|
|
655
|
+
|
|
656
|
+
- File issues and feature requests at the repository: `https://github.com/Walon-Foundation/monime-package/issues`.
|
|
657
|
+
- For production incidents, rotate credentials if you suspect exposure.
|
|
658
|
+
|
|
659
|
+
## TypeScript Types
|
|
660
|
+
|
|
661
|
+
All result payload types are exported from the package for complete type safety:
|
|
662
|
+
|
|
663
|
+
```ts
|
|
664
|
+
import type {
|
|
665
|
+
// Core types
|
|
666
|
+
ClientOptions,
|
|
667
|
+
|
|
668
|
+
// Financial Account types
|
|
669
|
+
CreateFinancialAccount,
|
|
670
|
+
GetFinancialAccount,
|
|
671
|
+
AllFinancialAccount,
|
|
672
|
+
|
|
673
|
+
// Internal Transfer types
|
|
674
|
+
CreateInternalTransfer,
|
|
675
|
+
InternalTransfer,
|
|
676
|
+
AllInternalTransfers,
|
|
677
|
+
|
|
678
|
+
// Payment Code types
|
|
679
|
+
CreatePaymentCode,
|
|
680
|
+
GetAllPaymentCode,
|
|
681
|
+
GetOne,
|
|
682
|
+
|
|
683
|
+
// Payout types
|
|
684
|
+
DestinationOption,
|
|
685
|
+
CreatePayout,
|
|
686
|
+
GetAll,
|
|
687
|
+
GetOnePayout,
|
|
688
|
+
|
|
689
|
+
// Financial Transaction types
|
|
690
|
+
GetTransaction,
|
|
691
|
+
AllTransaction,
|
|
692
|
+
|
|
693
|
+
// Checkout Session types
|
|
694
|
+
CreateCheckout,
|
|
695
|
+
AllCheckout,
|
|
696
|
+
OneCheckout,
|
|
697
|
+
} from "monime-package";
|
|
698
|
+
```
|
|
699
|
+
|
|
700
|
+
### Core Type Definitions
|
|
701
|
+
|
|
702
|
+
#### Result Envelope
|
|
703
|
+
All API responses follow this consistent pattern:
|
|
704
|
+
```ts
|
|
705
|
+
type Result<T> = {
|
|
706
|
+
success: boolean;
|
|
707
|
+
data?: T;
|
|
708
|
+
error?: Error;
|
|
709
|
+
};
|
|
710
|
+
```
|
|
711
|
+
|
|
712
|
+
#### Client Configuration
|
|
713
|
+
```ts
|
|
714
|
+
type ClientOptions = {
|
|
715
|
+
monimeSpaceId: string; // Your Monime Space ID
|
|
716
|
+
accessToken: string; // Your API access token
|
|
717
|
+
};
|
|
206
718
|
```
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
719
|
+
|
|
720
|
+
#### Destination Options for Payouts
|
|
721
|
+
```ts
|
|
722
|
+
type DestinationOption =
|
|
723
|
+
| {
|
|
724
|
+
type: "momo";
|
|
725
|
+
providerId: "m17" | "m18"; // MTN, Orange Money
|
|
726
|
+
phoneNumber: string;
|
|
727
|
+
}
|
|
728
|
+
| {
|
|
729
|
+
type: "bank";
|
|
730
|
+
providerId: "b01" | "b02" | "b03"; // Bank codes
|
|
731
|
+
accountNumber: string;
|
|
732
|
+
}
|
|
733
|
+
| {
|
|
734
|
+
type: "wallet";
|
|
735
|
+
providerId: "w01" | "w02"; // Wallet provider codes
|
|
736
|
+
walletId: string;
|
|
737
|
+
};
|
|
224
738
|
```
|
|
225
739
|
|
|
226
|
-
|
|
740
|
+
### Response Type Details
|
|
227
741
|
|
|
228
|
-
|
|
742
|
+
#### Financial Account Types
|
|
743
|
+
```ts
|
|
744
|
+
// Account creation/retrieval response
|
|
745
|
+
interface CreateFinancialAccount {
|
|
746
|
+
success: boolean;
|
|
747
|
+
messages: string[];
|
|
748
|
+
result: {
|
|
749
|
+
id: string; // Unique account ID
|
|
750
|
+
uvan: string; // Internal identifier
|
|
751
|
+
name: string; // Account name
|
|
752
|
+
currency: string; // Always "SLE" (Sierra Leone)
|
|
753
|
+
reference: string; // Account reference
|
|
754
|
+
description: string; // Account description
|
|
755
|
+
balance: {
|
|
756
|
+
available: {
|
|
757
|
+
currency: string;
|
|
758
|
+
value: number; // Balance in cents (SLE)
|
|
759
|
+
};
|
|
760
|
+
};
|
|
761
|
+
createTime: string; // ISO timestamp
|
|
762
|
+
updateTime: string; // ISO timestamp
|
|
763
|
+
};
|
|
764
|
+
}
|
|
765
|
+
```
|
|
766
|
+
|
|
767
|
+
#### Internal Transfer Types
|
|
768
|
+
```ts
|
|
769
|
+
interface CreateInternalTransfer {
|
|
770
|
+
success: boolean;
|
|
771
|
+
messages: string[];
|
|
772
|
+
result: {
|
|
773
|
+
id: string; // Transfer ID
|
|
774
|
+
status: string; // Transfer status
|
|
775
|
+
amount: {
|
|
776
|
+
currency: string;
|
|
777
|
+
value: number; // Amount in cents
|
|
778
|
+
};
|
|
779
|
+
sourceFinancialAccount: { id: string };
|
|
780
|
+
destinationFinancialAccount: { id: string };
|
|
781
|
+
financialTransactionReference: string;
|
|
782
|
+
description: string;
|
|
783
|
+
failureDetail: {
|
|
784
|
+
code: string;
|
|
785
|
+
message: string;
|
|
786
|
+
};
|
|
787
|
+
ownershipGraph: {
|
|
788
|
+
owner: {
|
|
789
|
+
id: string;
|
|
790
|
+
type: string;
|
|
791
|
+
owner: {
|
|
792
|
+
id: string;
|
|
793
|
+
type: string;
|
|
794
|
+
};
|
|
795
|
+
};
|
|
796
|
+
};
|
|
797
|
+
createTime: string;
|
|
798
|
+
updateTime: string;
|
|
799
|
+
};
|
|
800
|
+
}
|
|
801
|
+
```
|
|
229
802
|
|
|
230
|
-
|
|
231
|
-
|
|
803
|
+
#### Payment Code Types
|
|
804
|
+
```ts
|
|
805
|
+
interface CreatePaymentCode {
|
|
806
|
+
success: boolean;
|
|
807
|
+
messages: string[];
|
|
808
|
+
result: {
|
|
809
|
+
id: string;
|
|
810
|
+
mode: string; // "recurrent"
|
|
811
|
+
status: string; // Payment status
|
|
812
|
+
name: string; // Payment name
|
|
813
|
+
amount: {
|
|
814
|
+
currency: string;
|
|
815
|
+
value: number; // Amount in cents
|
|
816
|
+
};
|
|
817
|
+
enable: boolean;
|
|
818
|
+
expireTime: string; // ISO timestamp
|
|
819
|
+
customer: { name: string };
|
|
820
|
+
ussdCode: string; // USSD code for payment
|
|
821
|
+
reference: string;
|
|
822
|
+
authorizedProviders: string[];
|
|
823
|
+
authorizedPhoneNumber: string;
|
|
824
|
+
recurrentPaymentTarget: {
|
|
825
|
+
expectedPaymentCount: number;
|
|
826
|
+
expectedPaymentTotal: {
|
|
827
|
+
currency: string;
|
|
828
|
+
value: number;
|
|
829
|
+
};
|
|
830
|
+
};
|
|
831
|
+
financialAccountId: string;
|
|
832
|
+
processedPaymentData: {
|
|
833
|
+
amount: { currency: string; value: number };
|
|
834
|
+
orderId: string;
|
|
835
|
+
paymentId: string;
|
|
836
|
+
orderNumber: string;
|
|
837
|
+
channelData: {
|
|
838
|
+
providerId: string;
|
|
839
|
+
accountId: string;
|
|
840
|
+
reference: string;
|
|
841
|
+
};
|
|
842
|
+
financialTransactionReference: string;
|
|
843
|
+
};
|
|
844
|
+
createTime: string;
|
|
845
|
+
updateTime: string;
|
|
846
|
+
ownershipGraph: OwnershipGraph;
|
|
847
|
+
};
|
|
848
|
+
}
|
|
849
|
+
```
|
|
850
|
+
|
|
851
|
+
#### Checkout Session Types
|
|
852
|
+
```ts
|
|
853
|
+
interface CreateCheckout {
|
|
854
|
+
success: boolean;
|
|
855
|
+
messages: string[];
|
|
856
|
+
result: {
|
|
857
|
+
id: string;
|
|
858
|
+
status: string;
|
|
859
|
+
name: string;
|
|
860
|
+
orderNumber: string; // Generated order number
|
|
861
|
+
reference: string;
|
|
862
|
+
description: string;
|
|
863
|
+
redirectUrl: string; // Checkout page URL
|
|
864
|
+
cancelUrl: string;
|
|
865
|
+
successUrl: string;
|
|
866
|
+
lineItems: {
|
|
867
|
+
data: Array<{
|
|
868
|
+
type: string;
|
|
869
|
+
id: string;
|
|
870
|
+
name: string;
|
|
871
|
+
price: { currency: string; value: number };
|
|
872
|
+
quantity: number;
|
|
873
|
+
reference: string;
|
|
874
|
+
description: string;
|
|
875
|
+
images: string[];
|
|
876
|
+
}>;
|
|
877
|
+
};
|
|
878
|
+
financialAccountId: string;
|
|
879
|
+
brandingOptions: {
|
|
880
|
+
primaryColor: string;
|
|
881
|
+
};
|
|
882
|
+
expireTime: string;
|
|
883
|
+
createTime: string;
|
|
884
|
+
ownershipGraph: OwnershipGraph;
|
|
885
|
+
};
|
|
886
|
+
}
|
|
887
|
+
```
|
|
888
|
+
|
|
889
|
+
#### Common Types
|
|
890
|
+
```ts
|
|
891
|
+
// Pagination for list responses
|
|
892
|
+
interface Pagination {
|
|
893
|
+
count: number; // Total count
|
|
894
|
+
next: string; // Next page URL/cursor
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
// Ownership information
|
|
898
|
+
interface OwnershipGraph {
|
|
899
|
+
owner: {
|
|
900
|
+
id: string;
|
|
901
|
+
type: string;
|
|
902
|
+
owner: {
|
|
903
|
+
id: string;
|
|
904
|
+
type: string;
|
|
905
|
+
};
|
|
906
|
+
};
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
// Amount representation
|
|
910
|
+
interface Amount {
|
|
911
|
+
currency: string; // Always "SLE"
|
|
912
|
+
value: number; // Amount in cents (multiply by 100 for SLE)
|
|
913
|
+
}
|
|
914
|
+
```
|
|
915
|
+
|
|
916
|
+
### Type Usage Examples
|
|
917
|
+
|
|
918
|
+
```ts
|
|
919
|
+
// Type-safe account creation
|
|
920
|
+
const createAccountTyped = async (name: string): Promise<CreateFinancialAccount | null> => {
|
|
921
|
+
const result = await client.financialAccount.create(name);
|
|
922
|
+
return result.success ? result.data! : null;
|
|
923
|
+
};
|
|
924
|
+
|
|
925
|
+
// Type-safe payout with validation
|
|
926
|
+
const createMobileMoneyPayout = async (
|
|
927
|
+
amount: number,
|
|
928
|
+
phoneNumber: string,
|
|
929
|
+
sourceAccount: string
|
|
930
|
+
): Promise<CreatePayout | null> => {
|
|
931
|
+
const destination: DestinationOption = {
|
|
932
|
+
type: "momo",
|
|
933
|
+
providerId: "m17",
|
|
934
|
+
phoneNumber,
|
|
935
|
+
};
|
|
936
|
+
|
|
937
|
+
const result = await client.payout.create(amount, destination, sourceAccount);
|
|
938
|
+
return result.success ? result.data! : null;
|
|
939
|
+
};
|
|
940
|
+
|
|
941
|
+
// Type-safe transaction processing
|
|
942
|
+
const processTransactions = async (): Promise<void> => {
|
|
943
|
+
const txResult = await client.financialTransaction.getAll();
|
|
944
|
+
|
|
945
|
+
if (txResult.success && txResult.data) {
|
|
946
|
+
const transactions: AllTransaction = txResult.data;
|
|
947
|
+
|
|
948
|
+
transactions.result.forEach((tx: GetTransaction['result']) => {
|
|
949
|
+
console.log(`Transaction ${tx.id}: ${tx.amount.value / 100} ${tx.amount.currency}`);
|
|
950
|
+
});
|
|
951
|
+
}
|
|
952
|
+
};
|
|
953
|
+
```
|
|
232
954
|
|
|
233
955
|
---
|
|
234
956
|
|