remita-checkout-client 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +253 -73
- package/dist/chunk-O2KJGHVA.mjs +343 -0
- package/dist/chunk-O2KJGHVA.mjs.map +1 -0
- package/dist/cli.d.mts +11 -0
- package/dist/cli.d.ts +11 -0
- package/dist/cli.js +548 -182
- package/dist/cli.js.map +1 -1
- package/dist/cli.mjs +448 -199
- package/dist/cli.mjs.map +1 -1
- package/dist/index.d.mts +145 -12
- package/dist/index.d.ts +145 -12
- package/dist/index.js +123 -29
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +16 -21
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -2
- package/dist/chunk-MGQQHIIZ.mjs +0 -275
- package/dist/chunk-MGQQHIIZ.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -1,30 +1,21 @@
|
|
|
1
1
|
# remita-checkout-client
|
|
2
2
|
|
|
3
|
-
A typed client for the Remita Checkout
|
|
4
|
-
|
|
3
|
+
A typed TypeScript client for the Remita Checkout API. It lets you accept
|
|
4
|
+
payments, run the full payment lifecycle, check payment status in real time, and
|
|
5
|
+
look up supported channels — from the browser or Node.js 18+.
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
Two clients are available:
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
- **`MerchantCheckoutClient`** — start a checkout and verify the result. Best for
|
|
10
|
+
storefronts and businesses that only need to accept payment for a sale.
|
|
11
|
+
- **`RemitaPlatformClient`** — the full payment lifecycle (pre-payment, fees,
|
|
12
|
+
initiation, authorization, validation, verification) plus channel lookups.
|
|
13
|
+
Best for payment facilitators, gateways, and platforms.
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
- `payment-status.service.ts`
|
|
15
|
+
## Requirements
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
sequencing are all solid; it's specifically the shape of each request/
|
|
20
|
-
response body that needs confirming.
|
|
21
|
-
|
|
22
|
-
The **environment auto-detection from key prefix** (`src/environment.ts`)
|
|
23
|
-
is also a guess (Stripe-style `pk_test_`/`pk_live_` conventions) — it has
|
|
24
|
-
not been verified against Remita's real key format. It intentionally never
|
|
25
|
-
silently resolves to `"production"` — an unrecognized prefix falls back to
|
|
26
|
-
`"qa"` and reports `detected: false` so you can log/warn on it. Until you
|
|
27
|
-
verify the real prefixes, pass `environment` explicitly and skip detection.
|
|
17
|
+
- Node.js 18 or newer, or a browser with `fetch` support.
|
|
18
|
+
- A Remita public key for your environment.
|
|
28
19
|
|
|
29
20
|
## Install
|
|
30
21
|
|
|
@@ -32,53 +23,178 @@ verify the real prefixes, pass `environment` explicitly and skip detection.
|
|
|
32
23
|
npm install remita-checkout-client
|
|
33
24
|
```
|
|
34
25
|
|
|
35
|
-
|
|
26
|
+
The package includes TypeScript types and works with both ESM and CommonJS.
|
|
27
|
+
|
|
28
|
+
## Environments
|
|
29
|
+
|
|
30
|
+
Choose the environment that matches your key:
|
|
31
|
+
|
|
32
|
+
| Environment | Base URL |
|
|
33
|
+
| ------------ | ----------------------------------------------------- |
|
|
34
|
+
| `qa` | `https://api-checkout-qa.systemspecsng.com/api/v1` |
|
|
35
|
+
| `demo` | `https://api-checkout-demo.systemspecsng.com/api/v1` |
|
|
36
|
+
| `production` | `https://api-checkout.systemspecsng.com/api/v1` |
|
|
37
|
+
|
|
38
|
+
Set the environment explicitly, especially for production.
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
import { RemitaPlatformClient } from "remita-checkout-client";
|
|
42
|
+
|
|
43
|
+
const client = new RemitaPlatformClient({
|
|
44
|
+
publicKey: process.env.REMITA_PUBLIC_KEY!,
|
|
45
|
+
environment: "qa",
|
|
46
|
+
});
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Your public key is sent in a request header. Keep secret keys out of browser
|
|
50
|
+
code, and always verify a payment on your server before fulfilling an order.
|
|
36
51
|
|
|
37
|
-
|
|
52
|
+
## Merchant checkout
|
|
53
|
+
|
|
54
|
+
Merchant payments use Remita's hosted inline checkout. The client loads Remita's
|
|
55
|
+
`payment-checkout.js`, then drives the global `RmPaymentEngine` — the same
|
|
56
|
+
integration as Remita's own inline sample — and can verify the payment
|
|
57
|
+
afterwards over REST.
|
|
38
58
|
|
|
39
59
|
```ts
|
|
40
|
-
import {
|
|
60
|
+
import { MerchantCheckoutClient } from "remita-checkout-client";
|
|
61
|
+
|
|
62
|
+
const checkout = new MerchantCheckoutClient({
|
|
63
|
+
publicKey: "MERCHANT_PUBLIC_KEY",
|
|
64
|
+
environment: "production",
|
|
65
|
+
});
|
|
41
66
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
67
|
+
// Loads Remita's checkout script once and calls RmPaymentEngine.init.
|
|
68
|
+
const engine = await checkout.init({
|
|
69
|
+
paymentIdentifier: 788885554,
|
|
70
|
+
customerId: "abc@ya.com",
|
|
71
|
+
firstName: "Mike",
|
|
72
|
+
lastName: "Mike",
|
|
73
|
+
email: "abc@ya.com",
|
|
74
|
+
phoneNumber: "08067493797",
|
|
75
|
+
amount: "3000",
|
|
76
|
+
narration: "Test Payment",
|
|
77
|
+
currency: "NGN",
|
|
78
|
+
// channels: "TRANSFER",
|
|
79
|
+
onSuccess: (response) => console.log("success", response),
|
|
80
|
+
onError: (response) => console.log("error", response),
|
|
81
|
+
onClose: () => console.log("closed"),
|
|
47
82
|
});
|
|
48
83
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const initiated = await client.initiatePayment({ publicKey: client.publicKey, amount: 5000, channel: "card" });
|
|
84
|
+
engine.openIframe();
|
|
85
|
+
```
|
|
52
86
|
|
|
87
|
+
After the customer completes payment, verify it on your server before
|
|
88
|
+
fulfilling the order:
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
const verified = await checkout.verifyPayment("PAYMENT_REF_FROM_REMITA");
|
|
92
|
+
if (verified.status === "APPROVED") {
|
|
93
|
+
// Confirm the order on your backend before fulfilling it.
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
To collect an existing Remita Retrieval Reference (RRR) instead, use
|
|
98
|
+
`processRRR`, which mirrors `RmPaymentEngine.processRRR`:
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
const engine = await checkout.processRRR({
|
|
102
|
+
rrr: "927227066514",
|
|
103
|
+
paymentIdentifier: "7888855540094893435734834935035408",
|
|
104
|
+
channels: "",
|
|
105
|
+
onSuccess: (response) => console.log("success", response),
|
|
106
|
+
onError: (response) => console.log("error", response),
|
|
107
|
+
onClose: () => console.log("closed"),
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
engine.openIframe();
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
The hosted checkout is browser-only. `init`, `createCheckoutSession`,
|
|
114
|
+
`createSession`, and `processRRR` return the `RmPaymentEngine` instance, so you
|
|
115
|
+
call `openIframe()` to display it exactly like the script tag example. The
|
|
116
|
+
script URL is chosen from the environment and can be overridden with
|
|
117
|
+
`scriptUrl`.
|
|
118
|
+
|
|
119
|
+
## Platform lifecycle
|
|
120
|
+
|
|
121
|
+
`RemitaPlatformClient` walks the full flow: pre-payment, fee, initiation,
|
|
122
|
+
authorization, validation, and verification.
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
import { RemitaPlatformClient } from "remita-checkout-client";
|
|
126
|
+
|
|
127
|
+
const remita = new RemitaPlatformClient({
|
|
128
|
+
publicKey: "PSP_PUBLIC_KEY",
|
|
129
|
+
environment: "production",
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
const pre = await remita.prePayment({
|
|
133
|
+
firstName: "Ada",
|
|
134
|
+
lastName: "Okafor",
|
|
135
|
+
email: "ada@example.com",
|
|
136
|
+
phoneNumber: "08000000000",
|
|
137
|
+
paymentIdentifier: "ORDER-123",
|
|
138
|
+
currency: "NGN",
|
|
139
|
+
amount: 25000,
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
const fee = await remita.calculateFee({ amount: 25000, channel: "card" });
|
|
143
|
+
|
|
144
|
+
const paymentIdentifier = pre.transactionId ?? pre.paymentReference;
|
|
145
|
+
if (!paymentIdentifier) throw new Error("Pre-payment did not return a transaction reference");
|
|
146
|
+
|
|
147
|
+
const initiated = await remita.initiatePayment({
|
|
148
|
+
amount: 25000,
|
|
149
|
+
paymentIdentifier,
|
|
150
|
+
paymentChannel: "CARD",
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
// Only when the payment processor asks for it:
|
|
53
154
|
if (initiated.actionUrl) {
|
|
54
|
-
await
|
|
155
|
+
await remita.authorize(initiated.actionUrl, { otp: "123456" });
|
|
156
|
+
await remita.validatePayment({ paymentReference: initiated.paymentReference, otp: "123456" });
|
|
55
157
|
}
|
|
56
158
|
|
|
57
|
-
const verified = await
|
|
159
|
+
const verified = await remita.verifyPayment(initiated.paymentReference!);
|
|
58
160
|
console.log(verified.status); // "APPROVED" | "PENDING" | "FAILED" | ...
|
|
59
161
|
```
|
|
60
162
|
|
|
61
|
-
###
|
|
163
|
+
### Tracking a payment with PaymentSession
|
|
164
|
+
|
|
165
|
+
`PaymentSession` carries the references between steps so you don't have to, and
|
|
166
|
+
tracks the current stage of the flow. Its `stage` becomes `verified` only when
|
|
167
|
+
the payment is `APPROVED` and `failed` when it is `FAILED`; a `PENDING` payment
|
|
168
|
+
leaves the stage unchanged.
|
|
62
169
|
|
|
63
170
|
```ts
|
|
64
|
-
import {
|
|
171
|
+
import { RemitaPlatformClient, PaymentSession } from "remita-checkout-client";
|
|
65
172
|
|
|
66
|
-
const client = new
|
|
173
|
+
const client = new RemitaPlatformClient({ publicKey: "YOUR_PUBLIC_KEY", environment: "qa" });
|
|
67
174
|
const session = new PaymentSession(client);
|
|
68
175
|
|
|
69
|
-
await session.pre({
|
|
70
|
-
|
|
71
|
-
|
|
176
|
+
await session.pre({
|
|
177
|
+
firstName: "Ada", lastName: "Okafor", email: "ada@example.com",
|
|
178
|
+
phoneNumber: "08000000000", paymentIdentifier: "ORDER-123",
|
|
179
|
+
currency: "NGN", amount: 25000,
|
|
180
|
+
});
|
|
181
|
+
await session.fee({ amount: 25000, channel: "card" });
|
|
182
|
+
|
|
183
|
+
const paymentIdentifier = session.transactionId ?? session.paymentReference;
|
|
184
|
+
if (!paymentIdentifier) throw new Error("Pre-payment did not return a transaction reference");
|
|
185
|
+
await session.initiate({ amount: 25000, paymentIdentifier, paymentChannel: "CARD" });
|
|
72
186
|
|
|
73
|
-
// actionUrl from initiate() is remembered automatically
|
|
187
|
+
// The actionUrl from initiate() is remembered automatically.
|
|
74
188
|
await session.authorize({ otp: "123456" });
|
|
75
189
|
await session.validate({ otp: "123456" });
|
|
76
190
|
|
|
77
|
-
const result = await session.verify();
|
|
191
|
+
const result = await session.verify();
|
|
78
192
|
console.log(session.stage, result.status);
|
|
79
193
|
```
|
|
80
194
|
|
|
81
|
-
|
|
195
|
+
## Real-time payment status
|
|
196
|
+
|
|
197
|
+
Follow a payment's status live with server-sent events:
|
|
82
198
|
|
|
83
199
|
```ts
|
|
84
200
|
const handle = client.streamPaymentStatus(trxRef, {
|
|
@@ -87,15 +203,10 @@ const handle = client.streamPaymentStatus(trxRef, {
|
|
|
87
203
|
onError: (err) => console.error("stream error:", err),
|
|
88
204
|
});
|
|
89
205
|
|
|
90
|
-
//
|
|
91
|
-
handle.close();
|
|
206
|
+
handle.close(); // when you're done
|
|
92
207
|
```
|
|
93
208
|
|
|
94
|
-
|
|
95
|
-
browser-only `EventSource` global), so it behaves the same in the browser
|
|
96
|
-
and in Node.
|
|
97
|
-
|
|
98
|
-
### Channel config endpoints
|
|
209
|
+
## Channel and configuration lookups
|
|
99
210
|
|
|
100
211
|
```ts
|
|
101
212
|
const banks = await client.getBankList();
|
|
@@ -103,36 +214,105 @@ const ussdCodes = await client.getUssdCodes();
|
|
|
103
214
|
const wallets = await client.getWalletTypes();
|
|
104
215
|
```
|
|
105
216
|
|
|
106
|
-
##
|
|
107
|
-
|
|
108
|
-
Global `fetch` isn't available before Node 18. Pass a `fetchImpl` explicitly:
|
|
217
|
+
## Command line
|
|
109
218
|
|
|
110
|
-
|
|
111
|
-
|
|
219
|
+
The package also installs a `remita-checkout` command with two groups:
|
|
220
|
+
`merchant` and `platform`.
|
|
112
221
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
environment: "qa",
|
|
116
|
-
fetchImpl: fetch as unknown as typeof globalThis.fetch,
|
|
117
|
-
});
|
|
222
|
+
```bash
|
|
223
|
+
remita-checkout <group> <command> [options]
|
|
118
224
|
```
|
|
119
225
|
|
|
120
|
-
|
|
226
|
+
### Merchant commands
|
|
227
|
+
|
|
228
|
+
| Command | Description |
|
|
229
|
+
| ------------------ | -------------------------------- |
|
|
230
|
+
| `merchant verify` | Verify a payment by reference |
|
|
231
|
+
| `merchant status` | Alias for `verify` |
|
|
232
|
+
|
|
233
|
+
Merchant checkout itself runs in the browser through the hosted
|
|
234
|
+
`RmPaymentEngine`, so there is no CLI command to start it — the CLI only checks
|
|
235
|
+
payment status.
|
|
236
|
+
|
|
237
|
+
### Platform commands
|
|
238
|
+
|
|
239
|
+
| Command | Description |
|
|
240
|
+
| -------------------- | --------------------------------------------- |
|
|
241
|
+
| `platform pre` | Pre-payment initialization |
|
|
242
|
+
| `platform fee` | Calculate the fee for a channel |
|
|
243
|
+
| `platform initiate` | Initiate a payment |
|
|
244
|
+
| `platform authorize` | Submit authorization details |
|
|
245
|
+
| `platform validate` | Complete second-factor authorization (OTP) |
|
|
246
|
+
| `platform verify` | Verify payment status by reference |
|
|
247
|
+
| `platform stream` | Stream real-time status updates |
|
|
248
|
+
| `platform banks` | List supported banks |
|
|
249
|
+
| `platform ussd` | List USSD codes |
|
|
250
|
+
| `platform wallets` | List wallet types |
|
|
251
|
+
|
|
252
|
+
### Options
|
|
253
|
+
|
|
254
|
+
| Option | Description |
|
|
255
|
+
| ----------------------------- | --------------------------------------------------- |
|
|
256
|
+
| `--key <publicKey>` | Remita public key (required for most commands) |
|
|
257
|
+
| `--env <qa\|demo\|production>`| Environment to use |
|
|
258
|
+
| `--payment-identifier <ref>` | Reference from the payment flow |
|
|
259
|
+
| `--payment-channel <channel>` | Payment channel, e.g. `CARD` |
|
|
260
|
+
| `--payload <json>` | Additional details as JSON |
|
|
261
|
+
| `--show-payload` | Preview the request with sensitive fields redacted |
|
|
262
|
+
| `--json` | Print raw JSON, useful for piping |
|
|
263
|
+
|
|
264
|
+
### Examples
|
|
121
265
|
|
|
122
|
-
|
|
266
|
+
```bash
|
|
267
|
+
remita-checkout merchant verify --key QA-abc123 --ref PAY-REF-1 --json
|
|
268
|
+
remita-checkout platform pre --key QA-abc123 --rrr 123456789
|
|
269
|
+
remita-checkout platform verify --key QA-abc123 --ref PAY-REF-1 --json
|
|
270
|
+
```
|
|
123
271
|
|
|
124
|
-
-
|
|
125
|
-
|
|
126
|
-
return listener endpoint)
|
|
272
|
+
Only use Remita-approved test data in QA. Never pass real card details on the
|
|
273
|
+
command line — `--show-payload` redacts them, but shell history does not.
|
|
127
274
|
|
|
128
|
-
|
|
129
|
-
CyberSource's Accept.js script loading) — worth their own follow-up rather
|
|
130
|
-
than bolting on here.
|
|
275
|
+
## Errors
|
|
131
276
|
|
|
132
|
-
|
|
277
|
+
Failed requests throw a `RemitaApiError` that includes the HTTP status and the
|
|
278
|
+
error details returned by the API:
|
|
133
279
|
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
280
|
+
```ts
|
|
281
|
+
import { RemitaApiError } from "remita-checkout-client";
|
|
282
|
+
|
|
283
|
+
try {
|
|
284
|
+
await client.verifyPayment("PAYMENT_REF");
|
|
285
|
+
} catch (error) {
|
|
286
|
+
if (error instanceof RemitaApiError) {
|
|
287
|
+
console.error(error.status, error.message, error.payload);
|
|
288
|
+
} else {
|
|
289
|
+
throw error;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
138
292
|
```
|
|
293
|
+
|
|
294
|
+
## API coverage
|
|
295
|
+
|
|
296
|
+
| Operation | Method and path |
|
|
297
|
+
| ---------------------------- | --------------------------------------------------- |
|
|
298
|
+
| Pre-payment | `POST /payment/pre` |
|
|
299
|
+
| Fee calculation | `POST /payment/pre/feeCharge` |
|
|
300
|
+
| Initiate / merchant checkout | `POST /payment/initiate` |
|
|
301
|
+
| Authorize | `POST` to the action URL returned by initiation |
|
|
302
|
+
| Validate payment | `POST /payment/validate` |
|
|
303
|
+
| Verify payment | `GET /payment/verify/{reference}` |
|
|
304
|
+
| Payment status stream | `GET /payment/status/stream/{transactionReference}` |
|
|
305
|
+
| Bank list | `GET /payment/bank-list` |
|
|
306
|
+
| USSD codes | `GET /misc/ussd-codes` |
|
|
307
|
+
| Wallet types | `GET /misc/wallet-type` |
|
|
308
|
+
|
|
309
|
+
## Notes
|
|
310
|
+
|
|
311
|
+
- Google Pay / Apple Pay configuration and the CyberSource / Cardinal 3DS iframe
|
|
312
|
+
flow are not included in this version.
|
|
313
|
+
- Confirm request and response details against Remita's current API
|
|
314
|
+
documentation for your environment before going live.
|
|
315
|
+
|
|
316
|
+
## License
|
|
317
|
+
|
|
318
|
+
MIT
|