spaark-payapi-sdk 1.5.0 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +463 -65
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/index.mjs.map +1 -1
- package/dist/react.js +2 -2
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +2 -2
- package/dist/react.mjs.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,9 +1,34 @@
|
|
|
1
1
|
# spaark-payapi-sdk
|
|
2
2
|
|
|
3
|
-
TypeScript SDK for Pawapay Mobile Money API (V2). Simplifies integration with Mobile Money operators in Africa.
|
|
3
|
+
TypeScript SDK for Pawapay Mobile Money API (V2). Simplifies integration with Mobile Money operators in Africa (CEMAC region).
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/spaark-payapi-sdk)
|
|
6
6
|
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
[](https://www.typescriptlang.org/)
|
|
8
|
+
|
|
9
|
+
## Table of Contents
|
|
10
|
+
|
|
11
|
+
- [Installation](#installation)
|
|
12
|
+
- [Quick Start](#quick-start)
|
|
13
|
+
- [Features](#features)
|
|
14
|
+
- [Project Architecture](#project-architecture)
|
|
15
|
+
- [Supported Providers](#supported-providers)
|
|
16
|
+
- [API Reference](#api-reference)
|
|
17
|
+
- [Initialization](#initialization)
|
|
18
|
+
- [Transactions](#transactions)
|
|
19
|
+
- [Toolkit](#toolkit)
|
|
20
|
+
- [Finances](#finances)
|
|
21
|
+
- [Webhooks](#webhooks)
|
|
22
|
+
- [Products](#products)
|
|
23
|
+
- [Utilities](#utilities)
|
|
24
|
+
- [React Components](#react-components)
|
|
25
|
+
- [Test Dashboard](#test-dashboard)
|
|
26
|
+
- [Finance Dashboard](#finance-dashboard)
|
|
27
|
+
- [TypeScript Types](#typescript-types)
|
|
28
|
+
- [Error Handling](#error-handling)
|
|
29
|
+
- [Environment Variables](#environment-variables)
|
|
30
|
+
- [Development](#development)
|
|
31
|
+
- [License](#license)
|
|
7
32
|
|
|
8
33
|
## Installation
|
|
9
34
|
|
|
@@ -18,13 +43,24 @@ pnpm add spaark-payapi-sdk
|
|
|
18
43
|
yarn add spaark-payapi-sdk
|
|
19
44
|
```
|
|
20
45
|
|
|
21
|
-
### For React Components
|
|
46
|
+
### For React Components (shadcn/ui)
|
|
22
47
|
|
|
23
|
-
The SDK includes React components
|
|
48
|
+
The SDK includes React components built with shadcn/ui patterns. Install the required peer dependencies:
|
|
24
49
|
|
|
25
50
|
```bash
|
|
26
|
-
#
|
|
27
|
-
npm install react react-dom
|
|
51
|
+
# Core React dependencies
|
|
52
|
+
npm install react react-dom axios
|
|
53
|
+
|
|
54
|
+
# shadcn/ui prerequisites (via shadcn CLI)
|
|
55
|
+
pnpm dlx shadcn@latest add button
|
|
56
|
+
pnpm dlx shadcn@latest add tabs
|
|
57
|
+
pnpm dlx shadcn@latest add select
|
|
58
|
+
pnpm dlx shadcn@latest add chart
|
|
59
|
+
pnpm dlx shadcn@latest add skeleton
|
|
60
|
+
pnpm dlx shadcn@latest add spinner
|
|
61
|
+
|
|
62
|
+
# Or install manually (lucide-react is required for icons)
|
|
63
|
+
npm install lucide-react @radix-ui/react-tabs @radix-ui/react-select @radix-ui/react-dialog recharts @tanstack/react-table
|
|
28
64
|
|
|
29
65
|
# The following are bundled with the SDK (no need to install):
|
|
30
66
|
# - clsx
|
|
@@ -32,6 +68,8 @@ npm install react react-dom lucide-react @radix-ui/react-tabs @radix-ui/react-se
|
|
|
32
68
|
# - class-variance-authority
|
|
33
69
|
```
|
|
34
70
|
|
|
71
|
+
> **Note**: The components use shadcn/ui styling conventions. Make sure your project has Tailwind CSS configured with the shadcn/ui theme variables.
|
|
72
|
+
|
|
35
73
|
## Quick Start
|
|
36
74
|
|
|
37
75
|
```typescript
|
|
@@ -57,24 +95,94 @@ console.log(deposit.depositId, deposit.status);
|
|
|
57
95
|
|
|
58
96
|
## Features
|
|
59
97
|
|
|
60
|
-
|
|
61
|
-
- **
|
|
98
|
+
### Core SDK
|
|
99
|
+
- **Transactions**: Deposits, Payouts, Refunds, Payment Page, Polling
|
|
100
|
+
- **Toolkit**: Predict Provider, Active Configuration, Provider Availability, Public Keys
|
|
62
101
|
- **Finances**: Wallet Balances, Statement Generation
|
|
63
|
-
- **Webhooks**:
|
|
64
|
-
- **
|
|
65
|
-
|
|
102
|
+
- **Webhooks**: HMAC-SHA256 signature verification, Event parsing
|
|
103
|
+
- **Products**: Product management with domain configuration
|
|
104
|
+
|
|
105
|
+
### React Components
|
|
106
|
+
- **Test Dashboard**: Interactive SDK testing UI with 4 modes and 6 tabs
|
|
107
|
+
- **Demo Mode**: Finance Dashboard with mock data (no API key required)
|
|
108
|
+
- **Demo Expert**: Test Dashboard with simulated API responses (no API key required)
|
|
109
|
+
- **Sandbox Mode**: Finance Dashboard connected to Pawapay sandbox API
|
|
110
|
+
- **Production Mode**: Finance Dashboard connected to Pawapay production API
|
|
111
|
+
- **Finance Dashboard**: Transaction analytics with charts and KPIs
|
|
112
|
+
- **Icons**: lucide-react icons throughout the UI
|
|
113
|
+
- **shadcn/ui Components**: Button, Tabs, Select, Card, Input, Table, Skeleton, Spinner
|
|
114
|
+
- **Charts**: Area, Bar, Pie charts with Recharts
|
|
66
115
|
- **i18n**: French/English support
|
|
67
116
|
|
|
117
|
+
### Developer Experience
|
|
118
|
+
- **Full TypeScript**: Complete type definitions with strict mode
|
|
119
|
+
- **Zod Validation**: Input validation for all requests
|
|
120
|
+
- **Retry Logic**: Exponential backoff with jitter
|
|
121
|
+
- **Logging**: Configurable log levels with sensitive data sanitization
|
|
122
|
+
- **Error Handling**: Typed errors with retryable flag
|
|
123
|
+
|
|
124
|
+
## Project Architecture
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
src/
|
|
128
|
+
├── sdk.ts # Main SpaarkPayApiSdk class
|
|
129
|
+
├── config.ts # Configuration validation (Zod)
|
|
130
|
+
├── index.ts # Main exports
|
|
131
|
+
├── react.tsx # React components entry point
|
|
132
|
+
│
|
|
133
|
+
├── modules/
|
|
134
|
+
│ ├── transactions.ts # Deposits, payouts, refunds, polling
|
|
135
|
+
│ ├── products.ts # Product management
|
|
136
|
+
│ ├── webhooks.ts # Signature verification, event parsing
|
|
137
|
+
│ ├── utils.ts # Helpers, availability, prediction
|
|
138
|
+
│ └── finances.ts # Wallet balances, statements
|
|
139
|
+
│
|
|
140
|
+
├── core/
|
|
141
|
+
│ ├── http-client.ts # Axios wrapper with interceptors
|
|
142
|
+
│ ├── retry.ts # Exponential backoff logic
|
|
143
|
+
│ ├── errors.ts # PawapayError class
|
|
144
|
+
│ └── logger.ts # Configurable logger
|
|
145
|
+
│
|
|
146
|
+
├── types/
|
|
147
|
+
│ ├── config.ts # SDK configuration types
|
|
148
|
+
│ ├── transactions.ts # Transaction types
|
|
149
|
+
│ ├── webhooks.ts # Webhook event types
|
|
150
|
+
│ ├── toolkit.ts # Toolkit types
|
|
151
|
+
│ ├── finances.ts # Finance types
|
|
152
|
+
│ └── products.ts # Product types
|
|
153
|
+
│
|
|
154
|
+
├── constants/
|
|
155
|
+
│ ├── correspondents.ts # Provider definitions & limits
|
|
156
|
+
│ └── errors.ts # Error code definitions
|
|
157
|
+
│
|
|
158
|
+
├── components/
|
|
159
|
+
│ └── SpaarkPaySdkFinanceDashboard.tsx
|
|
160
|
+
│
|
|
161
|
+
├── mocks/
|
|
162
|
+
│ └── webhook-generators.ts # Test webhook generation
|
|
163
|
+
│
|
|
164
|
+
└── lib/
|
|
165
|
+
└── utils.ts # Tailwind merge utility
|
|
166
|
+
```
|
|
167
|
+
|
|
68
168
|
## Supported Providers
|
|
69
169
|
|
|
70
|
-
| Provider | Country | Currency |
|
|
71
|
-
|
|
72
|
-
| `MTN_MOMO_CMR` | Cameroon | XAF |
|
|
73
|
-
| `ORANGE_CMR` | Cameroon | XAF |
|
|
74
|
-
| `MTN_MOMO_COG` | Congo | XAF |
|
|
75
|
-
| `AIRTEL_COG` | Congo | XAF |
|
|
76
|
-
| `MTN_MOMO_GAB` | Gabon | XAF |
|
|
77
|
-
| `AIRTEL_GAB` | Gabon | XAF |
|
|
170
|
+
| Provider | Country | Currency | Deposits | Payouts |
|
|
171
|
+
|----------|---------|----------|----------|---------|
|
|
172
|
+
| `MTN_MOMO_CMR` | Cameroon | XAF | 100 - 1,000,000 | 500 - 500,000 |
|
|
173
|
+
| `ORANGE_CMR` | Cameroon | XAF | 100 - 1,000,000 | 500 - 500,000 |
|
|
174
|
+
| `MTN_MOMO_COG` | Congo | XAF | 100 - 1,000,000 | 500 - 500,000 |
|
|
175
|
+
| `AIRTEL_COG` | Congo | XAF | 100 - 1,000,000 | 500 - 500,000 |
|
|
176
|
+
| `MTN_MOMO_GAB` | Gabon | XAF | 100 - 1,000,000 | 500 - 500,000 |
|
|
177
|
+
| `AIRTEL_GAB` | Gabon | XAF | 100 - 1,000,000 | 500 - 500,000 |
|
|
178
|
+
|
|
179
|
+
### Phone Number Formats
|
|
180
|
+
|
|
181
|
+
| Country | Format | Example |
|
|
182
|
+
|---------|--------|---------|
|
|
183
|
+
| Cameroon | `237XXXXXXXXX` | 237670000000 |
|
|
184
|
+
| Congo | `242XXXXXXXXX` | 242060000000 |
|
|
185
|
+
| Gabon | `241XXXXXXXX` | 24160000000 |
|
|
78
186
|
|
|
79
187
|
## API Reference
|
|
80
188
|
|
|
@@ -84,12 +192,16 @@ console.log(deposit.depositId, deposit.status);
|
|
|
84
192
|
import { SpaarkPayApiSdk } from 'spaark-payapi-sdk';
|
|
85
193
|
|
|
86
194
|
const sdk = new SpaarkPayApiSdk({
|
|
87
|
-
apiKey: process.env.PAWAPAY_API_KEY,
|
|
88
|
-
environment: 'sandbox',
|
|
89
|
-
timeout: 30000,
|
|
90
|
-
retries: 3,
|
|
91
|
-
logLevel: 'info',
|
|
195
|
+
apiKey: process.env.PAWAPAY_API_KEY, // Required
|
|
196
|
+
environment: 'sandbox', // 'sandbox' | 'production'
|
|
197
|
+
timeout: 30000, // Request timeout in ms (default: 30000)
|
|
198
|
+
retries: 3, // Retry attempts (default: 3)
|
|
199
|
+
logLevel: 'info', // 'debug' | 'info' | 'warn' | 'error' | 'none'
|
|
92
200
|
});
|
|
201
|
+
|
|
202
|
+
// Runtime configuration
|
|
203
|
+
sdk.setLogLevel('debug');
|
|
204
|
+
sdk.setWebhookSecret('whsec_xxxxxxxxxxxx');
|
|
93
205
|
```
|
|
94
206
|
|
|
95
207
|
### Transactions
|
|
@@ -102,10 +214,10 @@ const deposit = await sdk.transactions.initiateDeposit({
|
|
|
102
214
|
currency: 'XAF',
|
|
103
215
|
provider: 'MTN_MOMO_CMR',
|
|
104
216
|
phoneNumber: '237670000000',
|
|
105
|
-
transactionId: sdk.utils.generateTransactionId(),
|
|
106
|
-
customerMessage: 'Payment description',
|
|
107
|
-
clientReferenceId: 'order-123',
|
|
108
|
-
metadata: [{ orderId: 'ORD-123' }],
|
|
217
|
+
transactionId: sdk.utils.generateTransactionId(), // UUID v4 required
|
|
218
|
+
customerMessage: 'Payment description', // 4-22 chars
|
|
219
|
+
clientReferenceId: 'order-123', // Optional
|
|
220
|
+
metadata: [{ orderId: 'ORD-123' }], // Optional
|
|
109
221
|
});
|
|
110
222
|
|
|
111
223
|
// Response
|
|
@@ -153,8 +265,8 @@ const status = await sdk.transactions.checkStatus('transaction-uuid');
|
|
|
153
265
|
|
|
154
266
|
```typescript
|
|
155
267
|
const result = await sdk.transactions.pollUntilComplete('transaction-uuid', {
|
|
156
|
-
interval: 5000, // Poll every 5 seconds
|
|
157
|
-
maxAttempts: 12, // Max 12 attempts (
|
|
268
|
+
interval: 5000, // Poll every 5 seconds (default)
|
|
269
|
+
maxAttempts: 12, // Max 12 attempts (default)
|
|
158
270
|
onStatusChange: (status) => console.log('Status:', status),
|
|
159
271
|
});
|
|
160
272
|
```
|
|
@@ -177,7 +289,7 @@ const page = await sdk.transactions.createPaymentPage({
|
|
|
177
289
|
returnUrl: 'https://yoursite.com/payment/complete',
|
|
178
290
|
phoneNumber: '237670000000', // Optional
|
|
179
291
|
amountDetails: { amount: 5000, currency: 'XAF' }, // Optional
|
|
180
|
-
language: 'FR', // Optional
|
|
292
|
+
language: 'FR', // Optional: 'FR' | 'EN'
|
|
181
293
|
country: 'CMR', // Optional
|
|
182
294
|
reason: 'Ticket purchase', // Optional
|
|
183
295
|
});
|
|
@@ -208,7 +320,7 @@ const prediction = await sdk.utils.predictProvider('+237 670 000 000');
|
|
|
208
320
|
```typescript
|
|
209
321
|
const availability = await sdk.utils.getProviderAvailability({
|
|
210
322
|
country: 'CMR', // Optional
|
|
211
|
-
operationType: 'DEPOSIT', // Optional
|
|
323
|
+
operationType: 'DEPOSIT', // Optional: 'DEPOSIT' | 'PAYOUT' | 'REFUND'
|
|
212
324
|
});
|
|
213
325
|
```
|
|
214
326
|
|
|
@@ -216,6 +328,7 @@ const availability = await sdk.utils.getProviderAvailability({
|
|
|
216
328
|
|
|
217
329
|
```typescript
|
|
218
330
|
const config = await sdk.utils.getActiveConfiguration();
|
|
331
|
+
// Returns company config, countries, providers, currencies, limits
|
|
219
332
|
```
|
|
220
333
|
|
|
221
334
|
#### Check MMO Availability
|
|
@@ -225,6 +338,13 @@ const status = await sdk.utils.checkMMOAvailability('MTN_MOMO_CMR');
|
|
|
225
338
|
// { correspondent: 'MTN_MOMO_CMR', available: true, degraded: false }
|
|
226
339
|
```
|
|
227
340
|
|
|
341
|
+
#### Get Public Keys
|
|
342
|
+
|
|
343
|
+
```typescript
|
|
344
|
+
const keys = await sdk.utils.getPublicKeys();
|
|
345
|
+
// [{ id: 'key-001', key: 'MIIBIjANBgkqhkiG9w0BAQEFAA...' }]
|
|
346
|
+
```
|
|
347
|
+
|
|
228
348
|
### Finances
|
|
229
349
|
|
|
230
350
|
#### Wallet Balances
|
|
@@ -245,22 +365,51 @@ const statement = await sdk.finances.generateStatement({
|
|
|
245
365
|
compressed: true,
|
|
246
366
|
});
|
|
247
367
|
|
|
368
|
+
// Poll until complete
|
|
248
369
|
const result = await sdk.finances.pollStatementUntilComplete(statement.statementId);
|
|
249
370
|
console.log(result.downloadUrl);
|
|
250
371
|
```
|
|
251
372
|
|
|
252
373
|
### Webhooks
|
|
253
374
|
|
|
375
|
+
#### Setup
|
|
376
|
+
|
|
254
377
|
```typescript
|
|
255
|
-
// Set secret
|
|
378
|
+
// Set webhook secret
|
|
256
379
|
sdk.setWebhookSecret(process.env.PAWAPAY_WEBHOOK_SECRET);
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
#### Verify Signature
|
|
257
383
|
|
|
258
|
-
|
|
384
|
+
```typescript
|
|
259
385
|
const isValid = sdk.webhooks.verifySignature(body, signature);
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
#### Parse Event
|
|
260
389
|
|
|
261
|
-
|
|
390
|
+
```typescript
|
|
262
391
|
const event = sdk.webhooks.parseEvent(body);
|
|
263
392
|
|
|
393
|
+
// Or verify + parse in one step
|
|
394
|
+
const event = sdk.webhooks.constructEvent(body, signature);
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
#### Event Types
|
|
398
|
+
|
|
399
|
+
| Event Type | Description |
|
|
400
|
+
|------------|-------------|
|
|
401
|
+
| `deposit.accepted` | Deposit request accepted |
|
|
402
|
+
| `deposit.completed` | Deposit completed successfully |
|
|
403
|
+
| `deposit.failed` | Deposit failed |
|
|
404
|
+
| `payout.accepted` | Payout request accepted |
|
|
405
|
+
| `payout.completed` | Payout completed successfully |
|
|
406
|
+
| `payout.failed` | Payout failed |
|
|
407
|
+
| `refund.completed` | Refund completed successfully |
|
|
408
|
+
| `refund.failed` | Refund failed |
|
|
409
|
+
|
|
410
|
+
#### Handle Events
|
|
411
|
+
|
|
412
|
+
```typescript
|
|
264
413
|
switch (event.eventType) {
|
|
265
414
|
case 'deposit.completed':
|
|
266
415
|
console.log('Deposit completed:', event.data.depositId);
|
|
@@ -271,20 +420,54 @@ switch (event.eventType) {
|
|
|
271
420
|
case 'payout.completed':
|
|
272
421
|
console.log('Payout completed:', event.data.payoutId);
|
|
273
422
|
break;
|
|
423
|
+
case 'payout.failed':
|
|
424
|
+
console.log('Payout failed:', event.data.failureReason);
|
|
425
|
+
break;
|
|
274
426
|
}
|
|
275
427
|
```
|
|
276
428
|
|
|
429
|
+
### Products
|
|
430
|
+
|
|
431
|
+
Local product management (in-memory storage):
|
|
432
|
+
|
|
433
|
+
```typescript
|
|
434
|
+
// Create product
|
|
435
|
+
const product = await sdk.products.create({
|
|
436
|
+
name: 'Premium Plan',
|
|
437
|
+
price: 10000,
|
|
438
|
+
currency: 'XAF',
|
|
439
|
+
description: 'Monthly subscription',
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
// Get product
|
|
443
|
+
const product = await sdk.products.get('product-id');
|
|
444
|
+
|
|
445
|
+
// List products
|
|
446
|
+
const products = await sdk.products.list();
|
|
447
|
+
|
|
448
|
+
// Update product
|
|
449
|
+
await sdk.products.update('product-id', { price: 12000 });
|
|
450
|
+
|
|
451
|
+
// Delete product
|
|
452
|
+
await sdk.products.delete('product-id');
|
|
453
|
+
|
|
454
|
+
// Add/remove domains
|
|
455
|
+
await sdk.products.addDomain({ productId: 'product-id', domain: 'example.com' });
|
|
456
|
+
await sdk.products.removeDomain('product-id', 'example.com');
|
|
457
|
+
```
|
|
458
|
+
|
|
277
459
|
### Utilities
|
|
278
460
|
|
|
279
461
|
```typescript
|
|
280
|
-
// Generate UUID v4
|
|
462
|
+
// Generate UUID v4 transaction ID
|
|
281
463
|
const txId = sdk.utils.generateTransactionId();
|
|
282
464
|
|
|
283
|
-
// Validate transaction ID
|
|
465
|
+
// Validate transaction ID format
|
|
284
466
|
const isValid = sdk.utils.validateTransactionId(txId);
|
|
285
467
|
|
|
286
|
-
// Format phone number
|
|
468
|
+
// Format phone number for country
|
|
287
469
|
const phone = sdk.utils.formatPhoneNumber('670000000', 'CMR');
|
|
470
|
+
// '237670000000'
|
|
288
471
|
|
|
289
472
|
// Validate phone for provider
|
|
290
473
|
const isValid = sdk.utils.validatePhoneNumber('237670000000', 'MTN_MOMO_CMR');
|
|
@@ -292,10 +475,10 @@ const isValid = sdk.utils.validatePhoneNumber('237670000000', 'MTN_MOMO_CMR');
|
|
|
292
475
|
// Get provider info
|
|
293
476
|
const info = sdk.utils.getCorrespondentInfo('MTN_MOMO_CMR');
|
|
294
477
|
|
|
295
|
-
// Detect provider from phone
|
|
478
|
+
// Detect provider from phone number
|
|
296
479
|
const provider = sdk.utils.detectCorrespondent('237670000000');
|
|
297
480
|
|
|
298
|
-
// Get transaction limits
|
|
481
|
+
// Get transaction limits for provider
|
|
299
482
|
const limits = await sdk.utils.getTransactionLimits('MTN_MOMO_CMR');
|
|
300
483
|
```
|
|
301
484
|
|
|
@@ -303,27 +486,72 @@ const limits = await sdk.utils.getTransactionLimits('MTN_MOMO_CMR');
|
|
|
303
486
|
|
|
304
487
|
### Test Dashboard
|
|
305
488
|
|
|
489
|
+
Interactive testing UI with **4 operation modes** and 6 tabs (Deposit, Payout, Status, Toolkit, Finances, Webhooks).
|
|
490
|
+
|
|
491
|
+
#### Dashboard Modes
|
|
492
|
+
|
|
493
|
+
| Mode | Description | API Key Required |
|
|
494
|
+
|------|-------------|------------------|
|
|
495
|
+
| **Demo** | Finance Dashboard with mock/fake data | No |
|
|
496
|
+
| **Demo Expert** | Test Dashboard with simulated API responses | No |
|
|
497
|
+
| **Sandbox** | Finance Dashboard connected to Pawapay sandbox API | Yes |
|
|
498
|
+
| **Production** | Finance Dashboard connected to Pawapay production API | Yes |
|
|
499
|
+
|
|
306
500
|
```tsx
|
|
307
501
|
import { SpaarkPaySdkTestDashboard } from 'spaark-payapi-sdk/react';
|
|
308
502
|
|
|
309
503
|
export default function TestPage() {
|
|
310
504
|
return (
|
|
311
505
|
<SpaarkPaySdkTestDashboard
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
506
|
+
apiKey="pk_sandbox_xxx" // Optional: pre-configured API key
|
|
507
|
+
environment="sandbox" // 'sandbox' | 'production'
|
|
508
|
+
apiBasePath="/api/pawapay" // Backend proxy route
|
|
509
|
+
demoMode={false} // Start in demo mode (default: false)
|
|
315
510
|
onDepositComplete={(res) => console.log('Deposit:', res)}
|
|
316
511
|
onPayoutComplete={(res) => console.log('Payout:', res)}
|
|
317
512
|
onError={(err) => console.error(err)}
|
|
513
|
+
className="max-w-6xl mx-auto"
|
|
318
514
|
/>
|
|
319
515
|
);
|
|
320
516
|
}
|
|
321
517
|
```
|
|
322
518
|
|
|
323
|
-
|
|
519
|
+
**Mode Selection:**
|
|
520
|
+
- Without `apiKey` or `demoMode`: Shows mode selection screen
|
|
521
|
+
- With `demoMode={true}`: Starts directly in Demo mode
|
|
522
|
+
- With `apiKey` + `environment`: Starts in Sandbox or Production mode
|
|
523
|
+
|
|
524
|
+
#### Backend Proxy Setup (Next.js)
|
|
525
|
+
|
|
526
|
+
```typescript
|
|
527
|
+
// app/api/pawapay/deposit/route.ts
|
|
528
|
+
import { SpaarkPayApiSdk } from 'spaark-payapi-sdk';
|
|
529
|
+
|
|
530
|
+
export async function POST(request: Request) {
|
|
531
|
+
const body = await request.json();
|
|
532
|
+
|
|
533
|
+
const sdk = new SpaarkPayApiSdk({
|
|
534
|
+
apiKey: body.apiKey,
|
|
535
|
+
environment: body.environment,
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
const result = await sdk.transactions.initiateDeposit({
|
|
539
|
+
amount: body.amount,
|
|
540
|
+
currency: body.currency,
|
|
541
|
+
provider: body.provider,
|
|
542
|
+
phoneNumber: body.phoneNumber,
|
|
543
|
+
transactionId: body.transactionId,
|
|
544
|
+
customerMessage: body.customerMessage,
|
|
545
|
+
});
|
|
546
|
+
|
|
547
|
+
return Response.json(result);
|
|
548
|
+
}
|
|
549
|
+
```
|
|
324
550
|
|
|
325
551
|
### Finance Dashboard
|
|
326
552
|
|
|
553
|
+
Transaction analytics dashboard with KPI cards, filters, pagination, and charts.
|
|
554
|
+
|
|
327
555
|
```tsx
|
|
328
556
|
import {
|
|
329
557
|
SpaarkPaySdkFinanceDashboard,
|
|
@@ -341,54 +569,140 @@ const transactions: Transaction[] = [
|
|
|
341
569
|
phoneNumber: '237670000000',
|
|
342
570
|
createdAt: '2025-01-15T10:00:00Z',
|
|
343
571
|
},
|
|
344
|
-
// ... more transactions
|
|
345
572
|
];
|
|
346
573
|
|
|
347
574
|
export default function FinancePage() {
|
|
348
575
|
return (
|
|
349
576
|
<SpaarkPaySdkFinanceDashboard
|
|
350
577
|
transactions={transactions}
|
|
351
|
-
title="My Finance Dashboard"
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
578
|
+
title="My Finance Dashboard"
|
|
579
|
+
subtitle="Overview of your transactions"
|
|
580
|
+
locale="fr" // 'fr' | 'en'
|
|
581
|
+
onRefresh={() => fetchData()} // Refresh button callback
|
|
582
|
+
onSettings={() => openSettings()} // Settings button (gear icon)
|
|
583
|
+
onAddTransaction={() => openForm()} // CTA button when no transactions
|
|
584
|
+
onTransactionClick={(tx) => {}} // Table row click
|
|
585
|
+
onExpertModeClick={() => {}} // Expert mode button
|
|
586
|
+
showExpertMode={true}
|
|
587
|
+
isLoading={false}
|
|
358
588
|
/>
|
|
359
589
|
);
|
|
360
590
|
}
|
|
361
591
|
```
|
|
362
592
|
|
|
593
|
+
**Props:**
|
|
594
|
+
|
|
595
|
+
| Prop | Type | Description |
|
|
596
|
+
|------|------|-------------|
|
|
597
|
+
| `transactions` | `Transaction[]` | Array of transactions to display |
|
|
598
|
+
| `title` | `string` | Dashboard title (default: "Tableau de bord financier") |
|
|
599
|
+
| `subtitle` | `string` | Dashboard subtitle |
|
|
600
|
+
| `locale` | `'fr' \| 'en'` | Language (default: 'fr') |
|
|
601
|
+
| `onRefresh` | `() => void` | Refresh button callback |
|
|
602
|
+
| `onSettings` | `() => void` | Settings button callback (gear icon) |
|
|
603
|
+
| `onAddTransaction` | `() => void` | CTA button callback when no transactions |
|
|
604
|
+
| `onTransactionClick` | `(tx) => void` | Table row click callback |
|
|
605
|
+
| `onExpertModeClick` | `() => void` | Expert mode button callback |
|
|
606
|
+
| `showExpertMode` | `boolean` | Show/hide expert mode button |
|
|
607
|
+
| `isLoading` | `boolean` | Show loading skeletons |
|
|
608
|
+
|
|
363
609
|
**Features:**
|
|
364
|
-
|
|
610
|
+
|
|
611
|
+
**Dashboard Tab:**
|
|
612
|
+
- 8 KPI cards: Total Volume, Deposits, Payouts, Refunds, Pending, Completed, Failed, Cancelled
|
|
365
613
|
- Search by transaction ID or phone number
|
|
366
|
-
-
|
|
367
|
-
- Paginated transactions table
|
|
368
|
-
- Copy transaction ID
|
|
369
|
-
-
|
|
370
|
-
|
|
371
|
-
|
|
614
|
+
- Dropdown filters for type and status
|
|
615
|
+
- Paginated transactions table with @tanstack/react-table
|
|
616
|
+
- Copy transaction ID button
|
|
617
|
+
- Empty state with CTA button
|
|
618
|
+
|
|
619
|
+
**Charts Tab:**
|
|
620
|
+
- Area Chart: Volume over time (deposits vs payouts)
|
|
621
|
+
- Bar Chart: Transaction amounts by type
|
|
622
|
+
- Pie Chart: Status distribution (donut style)
|
|
372
623
|
|
|
373
624
|
## TypeScript Types
|
|
374
625
|
|
|
375
626
|
```typescript
|
|
376
627
|
import type {
|
|
628
|
+
// SDK Config
|
|
377
629
|
SpaarkPayApiSdkConfig,
|
|
630
|
+
ResolvedConfig,
|
|
631
|
+
Environment,
|
|
632
|
+
LogLevel,
|
|
633
|
+
|
|
634
|
+
// Transactions
|
|
378
635
|
DepositRequest,
|
|
379
636
|
DepositResponse,
|
|
380
637
|
PayoutRequest,
|
|
381
638
|
PayoutResponse,
|
|
639
|
+
RefundRequest,
|
|
640
|
+
RefundResponse,
|
|
382
641
|
TransactionStatus,
|
|
383
642
|
TransactionStatusResponse,
|
|
643
|
+
PaymentPageRequest,
|
|
644
|
+
PaymentPageResponse,
|
|
645
|
+
PollOptions,
|
|
646
|
+
FailureReason,
|
|
647
|
+
DepositFailureCode,
|
|
648
|
+
PayoutFailureCode,
|
|
649
|
+
|
|
650
|
+
// Providers
|
|
384
651
|
Correspondent,
|
|
652
|
+
CorrespondentInfo,
|
|
653
|
+
TransactionLimits,
|
|
385
654
|
Currency,
|
|
655
|
+
|
|
656
|
+
// Webhooks
|
|
657
|
+
WebhookEventType,
|
|
658
|
+
PawapayWebhookEvent,
|
|
659
|
+
DepositCallbackData,
|
|
660
|
+
PayoutCallbackData,
|
|
661
|
+
|
|
662
|
+
// Toolkit
|
|
663
|
+
OperationType,
|
|
664
|
+
OperationStatus,
|
|
665
|
+
ProviderAvailability,
|
|
666
|
+
ActiveConfigResponse,
|
|
667
|
+
PredictProviderResponse,
|
|
668
|
+
PublicKeyResponse,
|
|
669
|
+
|
|
670
|
+
// Finances
|
|
671
|
+
WalletBalance,
|
|
672
|
+
StatementRequest,
|
|
673
|
+
StatementResponse,
|
|
674
|
+
StatementStatus,
|
|
675
|
+
|
|
676
|
+
// Products
|
|
677
|
+
Product,
|
|
678
|
+
ProductCreateRequest,
|
|
679
|
+
|
|
680
|
+
// React Components
|
|
386
681
|
Transaction,
|
|
387
682
|
TransactionType,
|
|
388
|
-
|
|
683
|
+
SpaarkPaySdkFinanceDashboardProps,
|
|
684
|
+
SpaarkPaySdkTestDashboardProps,
|
|
389
685
|
} from 'spaark-payapi-sdk';
|
|
390
686
|
```
|
|
391
687
|
|
|
688
|
+
### Transaction Type (Finance Dashboard)
|
|
689
|
+
|
|
690
|
+
```typescript
|
|
691
|
+
type Transaction = {
|
|
692
|
+
id: string;
|
|
693
|
+
type: 'deposit' | 'payout' | 'refund';
|
|
694
|
+
amount: number;
|
|
695
|
+
currency: string;
|
|
696
|
+
status: 'ACCEPTED' | 'PENDING' | 'ENQUEUED' | 'PROCESSING' | 'COMPLETED' | 'FAILED' | 'CANCELLED' | 'REJECTED';
|
|
697
|
+
provider: Correspondent;
|
|
698
|
+
phoneNumber: string;
|
|
699
|
+
description?: string;
|
|
700
|
+
createdAt: string;
|
|
701
|
+
updatedAt?: string;
|
|
702
|
+
failureReason?: string;
|
|
703
|
+
};
|
|
704
|
+
```
|
|
705
|
+
|
|
392
706
|
## Error Handling
|
|
393
707
|
|
|
394
708
|
```typescript
|
|
@@ -398,22 +712,106 @@ try {
|
|
|
398
712
|
await sdk.transactions.initiateDeposit({ ... });
|
|
399
713
|
} catch (error) {
|
|
400
714
|
if (error instanceof PawapayError) {
|
|
401
|
-
console.log(error.code);
|
|
402
|
-
console.log(error.message);
|
|
403
|
-
console.log(error.retryable);
|
|
404
|
-
console.log(error.statusCode);
|
|
715
|
+
console.log(error.code); // Error code
|
|
716
|
+
console.log(error.message); // Human-readable message
|
|
717
|
+
console.log(error.retryable); // Whether to retry
|
|
718
|
+
console.log(error.statusCode); // HTTP status code
|
|
719
|
+
console.log(error.failureReason); // Pawapay failure reason
|
|
405
720
|
}
|
|
406
721
|
}
|
|
407
722
|
```
|
|
408
723
|
|
|
724
|
+
### Error Codes
|
|
725
|
+
|
|
726
|
+
| Code | Description | Retryable |
|
|
727
|
+
|------|-------------|-----------|
|
|
728
|
+
| `VALIDATION_ERROR` | Invalid input data | No |
|
|
729
|
+
| `INVALID_PHONE` | Invalid phone number format | No |
|
|
730
|
+
| `INSUFFICIENT_FUNDS` | Not enough balance | No |
|
|
731
|
+
| `AMOUNT_TOO_LOW` | Below minimum amount | No |
|
|
732
|
+
| `AMOUNT_TOO_HIGH` | Above maximum amount | No |
|
|
733
|
+
| `LIMIT_EXCEEDED` | Daily/monthly limit exceeded | No |
|
|
734
|
+
| `DUPLICATE` | Duplicate transaction ID | No |
|
|
735
|
+
| `MMO_UNAVAILABLE` | Provider is unavailable | Yes |
|
|
736
|
+
| `TIMEOUT` | Request timeout | Yes |
|
|
737
|
+
| `UNAUTHORIZED` | Invalid API key | No |
|
|
738
|
+
| `RATE_LIMITED` | Too many requests | Yes |
|
|
739
|
+
| `SERVER_ERROR` | Pawapay server error | Yes |
|
|
740
|
+
| `NETWORK_ERROR` | Network connectivity issue | Yes |
|
|
741
|
+
| `NOT_FOUND` | Transaction not found | No |
|
|
742
|
+
|
|
409
743
|
## Environment Variables
|
|
410
744
|
|
|
411
745
|
```bash
|
|
746
|
+
# Required
|
|
412
747
|
PAWAPAY_API_KEY=pk_sandbox_xxxxxxxxxxxx
|
|
413
|
-
|
|
414
|
-
|
|
748
|
+
|
|
749
|
+
# Optional
|
|
750
|
+
PAWAPAY_ENVIRONMENT=sandbox # 'sandbox' | 'production' (default: sandbox)
|
|
751
|
+
PAWAPAY_BASE_URL=https://custom.api.url # Custom API base URL
|
|
752
|
+
PAWAPAY_CALLBACK_URL=https://... # Default webhook callback URL
|
|
753
|
+
PAWAPAY_TIMEOUT=30000 # Request timeout in ms (default: 30000)
|
|
754
|
+
PAWAPAY_RETRIES=3 # Number of retries (default: 3)
|
|
755
|
+
PAWAPAY_LOG_LEVEL=info # 'debug' | 'info' | 'warn' | 'error' | 'none'
|
|
756
|
+
PAWAPAY_WEBHOOK_SECRET=whsec_xxx # Webhook signature secret
|
|
757
|
+
```
|
|
758
|
+
|
|
759
|
+
## Development
|
|
760
|
+
|
|
761
|
+
### Setup
|
|
762
|
+
|
|
763
|
+
```bash
|
|
764
|
+
# Clone repository
|
|
765
|
+
git clone https://github.com/confort-sept-inc/react-spaark-payapi-sdk.git
|
|
766
|
+
cd react-spaark-payapi-sdk
|
|
767
|
+
|
|
768
|
+
# Install dependencies
|
|
769
|
+
pnpm install
|
|
770
|
+
|
|
771
|
+
# Build
|
|
772
|
+
pnpm build
|
|
773
|
+
|
|
774
|
+
# Run tests
|
|
775
|
+
pnpm test
|
|
776
|
+
|
|
777
|
+
# Type check
|
|
778
|
+
pnpm typecheck
|
|
779
|
+
|
|
780
|
+
# Lint
|
|
781
|
+
pnpm lint
|
|
415
782
|
```
|
|
416
783
|
|
|
784
|
+
### Scripts
|
|
785
|
+
|
|
786
|
+
| Script | Description |
|
|
787
|
+
|--------|-------------|
|
|
788
|
+
| `pnpm build` | Build with tsup (ESM + CJS + types) |
|
|
789
|
+
| `pnpm dev` | Watch mode for development |
|
|
790
|
+
| `pnpm test` | Run Jest tests |
|
|
791
|
+
| `pnpm test:coverage` | Run tests with coverage |
|
|
792
|
+
| `pnpm typecheck` | TypeScript type checking |
|
|
793
|
+
| `pnpm lint` | ESLint |
|
|
794
|
+
| `pnpm release` | Build, version, and publish |
|
|
795
|
+
|
|
796
|
+
### Testing
|
|
797
|
+
|
|
798
|
+
```bash
|
|
799
|
+
# Run all tests
|
|
800
|
+
pnpm test
|
|
801
|
+
|
|
802
|
+
# Run with coverage (70% threshold)
|
|
803
|
+
pnpm test:coverage
|
|
804
|
+
|
|
805
|
+
# Run specific test file
|
|
806
|
+
pnpm test src/__tests__/sdk.test.ts
|
|
807
|
+
```
|
|
808
|
+
|
|
809
|
+
### Project Requirements
|
|
810
|
+
|
|
811
|
+
- Node.js >= 18.0.0
|
|
812
|
+
- TypeScript >= 5.3
|
|
813
|
+
- React 18 or 19 (for components)
|
|
814
|
+
|
|
417
815
|
## License
|
|
418
816
|
|
|
419
817
|
MIT
|