@valuepay/react 1.0.0 → 2.1.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 CHANGED
@@ -1,435 +1,545 @@
1
- # @valuepay/react
2
-
3
- > Official React SDK for [ValuePay](https://valuepayng.com) — accept payments in your React app with minimal setup.
4
-
5
- [![npm version](https://img.shields.io/npm/v/@valuepay/react.svg)](https://www.npmjs.com/package/@valuepay/react)
6
- [![license](https://img.shields.io/npm/l/@valuepay/react.svg)](LICENSE)
7
- [![coverage](https://img.shields.io/badge/coverage-90%25-brightgreen.svg)]()
8
- [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)]()
9
-
10
- ---
11
-
12
- ## Table of Contents
13
-
14
- - [Installation](#installation)
15
- - [Quick Start](#quick-start)
16
- - [Option 1: Drop-in Button](#option-1-drop-in-button-simplest)
17
- - [Option 2: Hook (Full Control)](#option-2-hook-full-control)
18
- - [Option 3: Provider with Ref](#option-3-provider-with-ref-hidden-component)
19
- - [Redirect Mode](#redirect-mode)
20
- - [API Reference](#api-reference)
21
- - [useValuePay](#usevaluepayconfig-valuepayconfig-usevaluepayreturn)
22
- - [ValuePayButton](#valuepaybutton--props)
23
- - [ValuePayProvider](#valuepayprovider--props)
24
- - [ValuePayConfig](#valuepayconfig)
25
- - [ValuePayResponse](#valuepayresponse)
26
- - [Dynamic Amounts](#dynamic-amounts)
27
- - [Payment Channels](#payment-channels)
28
- - [Customizing the Checkout Modal](#customizing-the-checkout-modal)
29
- - [Server-Side Verification](#server-side-verification)
30
- - [TypeScript](#typescript)
31
- - [Browser Support](#browser-support)
32
- - [Security](#security)
33
- - [Contributing](#contributing)
34
- - [License](#license)
35
-
36
- ---
37
-
38
- ## Installation
39
-
40
- ```bash
41
- npm install @valuepay/react
42
- # or
43
- yarn add @valuepay/react
44
- # or
45
- pnpm add @valuepay/react
46
- ```
47
-
48
- ### Requirements
49
-
50
- - **React** `>=16.8.0` (hooks support required)
51
- - **React DOM** `>=16.8.0`
52
-
53
- ---
54
-
55
- ## Quick Start
56
-
57
- ### Option 1: Drop-in Button (Simplest)
58
-
59
- ```tsx
60
- import { ValuePayButton } from "@valuepay/react";
61
-
62
- function Checkout() {
63
- return (
64
- <ValuePayButton
65
- publicKey="KP_your_public_key"
66
- amount={5000}
67
- customer={{ email: "jane@example.com", fullName: "Jane Doe" }}
68
- onSuccess={(response) => {
69
- console.log("Payment successful!", response.ref, response.status);
70
- }}
71
- onClose={(response) => {
72
- console.log("Checkout closed", response);
73
- }}
74
- onCancelled={(response) => {
75
- console.log("Payment cancelled", response);
76
- }}
77
- />
78
- );
79
- }
80
- ```
81
-
82
- The button renders as **"Pay ₦5,000 Now"** by default. Customize with `text`, `className`, `style`, or pass `children`.
83
-
84
- ### Option 2: Hook (Full Control)
85
-
86
- ```tsx
87
- import { useValuePay } from "@valuepay/react";
88
-
89
- function Checkout() {
90
- const { initialize, isReady, isProcessing } = useValuePay({
91
- publicKey: "KP_your_public_key",
92
- amount: 10000,
93
- customer: { email: "john@example.com", fullName: "John Doe" },
94
- onSuccess: (response) => {
95
- console.log("Paid!", response);
96
- // response.ref, response.status, response.amount, etc.
97
- },
98
- onCancelled: (response) => console.log("Cancelled", response),
99
- onClose: (response) => console.log("Closed", response),
100
- });
101
-
102
- return (
103
- <button onClick={() => initialize()} disabled={!isReady || isProcessing}>
104
- {isProcessing ? "Processing..." : "Pay ₦10,000"}
105
- </button>
106
- );
107
- }
108
- ```
109
-
110
- ### Option 3: Provider with Ref (Hidden Component)
111
-
112
- ```tsx
113
- import { useRef } from "react";
114
- import { ValuePayProvider, ValuePayProviderRef } from "@valuepay/react";
115
-
116
- function Checkout() {
117
- const payRef = useRef<ValuePayProviderRef>(null);
118
-
119
- const handlePay = () => {
120
- payRef.current?.initialize();
121
- };
122
-
123
- return (
124
- <>
125
- <ValuePayProvider
126
- ref={payRef}
127
- config={{
128
- publicKey: "KP_your_public_key",
129
- amount: 7500,
130
- customer: { email: "alice@example.com", fullName: "Alice Smith" },
131
- onSuccess: (response) => console.log("Success!", response),
132
- onCancelled: (response) => console.log("Cancelled", response),
133
- }}
134
- />
135
- <button onClick={handlePay}>Checkout</button>
136
- </>
137
- );
138
- }
139
- ```
140
-
141
- ---
142
-
143
- ## Redirect Mode
144
-
145
- Instead of callbacks, you can redirect the user after payment:
146
-
147
- ```tsx
148
- <ValuePayButton
149
- publicKey="KP_your_public_key"
150
- amount={5000}
151
- customer={{ email: "jane@example.com", fullName: "Jane Doe" }}
152
- redirectUrl="https://yoursite.com/payment/verify"
153
- />
154
- ```
155
-
156
- After payment, the user is redirected to:
157
-
158
- ```
159
- https://yoursite.com/payment/verify?ref=VPS_TX_abc123&status=SUCCESS
160
- ```
161
-
162
- Your server should then verify the transaction using the `ref` query parameter via the [ValuePay Verify API](https://developer.valuepayng.com/docs).
163
-
164
- ---
165
-
166
- ## API Reference
167
-
168
- ### `useValuePay(config: ValuePayConfig): UseValuePayReturn`
169
-
170
- | Return | Type | Description |
171
- | -------------- | ----------------------- | -------------------------------------------- |
172
- | `initialize` | `(overrides?) => void` | Opens the ValuePay checkout modal |
173
- | `isReady` | `boolean` | `true` when the ValuePay script has loaded |
174
- | `isProcessing` | `boolean` | `true` while a payment is in progress |
175
-
176
- ### `<ValuePayButton />` Props
177
-
178
- Extends `ValuePayConfig` with:
179
-
180
- | Prop | Type | Default | Description |
181
- | ----------- | ---------------- | ---------------------- | -------------------- |
182
- | `text` | `string` | `"Pay ₦{amount} Now"` | Button text |
183
- | `className` | `string` | — | CSS class |
184
- | `style` | `CSSProperties` | — | Inline styles |
185
- | `disabled` | `boolean` | `false` | Disable button |
186
- | `children` | `ReactNode` | — | Custom button content|
187
-
188
- ### `<ValuePayProvider />` Props
189
-
190
- | Prop | Type | Description |
191
- | -------- | ------------------------- | -------------------------------- |
192
- | `config` | `ValuePayConfig` | Payment configuration |
193
- | `ref` | `Ref<ValuePayProviderRef>`| Exposes `initialize()` method |
194
-
195
- ### `ValuePayConfig`
196
-
197
- | Prop | Type | Required | Default | Description |
198
- | ---------------- | ---------------------------- | -------- | ------------------------------------ | ---------------------------------- |
199
- | `publicKey` | `string` | Yes | — | Your ValuePay public key |
200
- | `amount` | `number` | Yes | — | Amount in Naira |
201
- | `customer` | `{ email, fullName, phone? }`| Yes | — | Customer details |
202
- | `currency` | `string` | | `"NGN"` | Currency code |
203
- | `channels` | `PaymentChannel[]` | — | `["card","transfer","qrcode","ussd"]`| Enabled channels |
204
- | `transactionRef` | `string` | — | Auto-generated | Unique transaction reference |
205
- | `redirectUrl` | `string` | — | — | Redirect URL after payment |
206
- | `metaData` | `Record<string, unknown>` | — | — | Custom metadata |
207
- | `customization` | `{ title?, description?, logoUrl? }` | — | — | Checkout modal branding |
208
- | `onSuccess` | `(response) => void` | — | — | Called on successful payment |
209
- | `onClose` | `(response) => void` | — | — | Called when modal is closed |
210
- | `onCancelled` | `(response) => void` | | | Called when payment is cancelled |
211
- | `onCallback` | `(response) => void` | — | | Called on any payment event |
212
- | `onError` | `(error) => void` | — | — | Called on SDK errors |
213
- | `scriptUrl` | `string` | — | Production CDN | Override ValuePay script URL |
214
-
215
- ### `ValuePayResponse`
216
-
217
- | Field | Type | Description |
218
- | ---------------- | ------------------ | --------------------------------------------------------------------------------------------- |
219
- | `ref` | `string` | Transaction reference |
220
- | `transactionRef` | `string` | Same as `ref` |
221
- | `status` | `ValuePayStatus` | `"SUCCESS"`, `"COMPLETED"`, `"FAILED"`, `"CANCELLED"`, `"DUPLICATE"`, `"PENDING"` |
222
- | `amount` | `number` | Transaction amount |
223
- | `currency` | `string` | Currency code |
224
- | `customer` | `ValuePayCustomer` | Customer details |
225
- | `paymentMethod` | `string?` | Payment method used |
226
- | `validation` | `{ status }?` | Server-side validation result |
227
- | `raw` | `unknown?` | Raw ValuePay response |
228
-
229
- ---
230
-
231
- ## Dynamic Amounts
232
-
233
- Override any config at call time:
234
-
235
- ```tsx
236
- const { initialize } = useValuePay({
237
- publicKey: "KP_xxx",
238
- amount: 0, // placeholder
239
- customer: { email: "user@example.com", fullName: "User" },
240
- onSuccess: (res) => console.log(res),
241
- });
242
-
243
- // Later, with dynamic amount:
244
- initialize({ amount: selectedProduct.price });
245
- ```
246
-
247
- ---
248
-
249
- ## Payment Channels
250
-
251
- | Channel | Value |
252
- | -------------- | ---------------- |
253
- | Card | `"card"` |
254
- | Bank Transfer | `"transfer"` |
255
- | QR Code | `"qrcode"` |
256
- | USSD | `"ussd"` |
257
- | Mobile Money | `"mobile_money"` |
258
-
259
- ---
260
-
261
- ## Customizing the Checkout Modal
262
-
263
- ```tsx
264
- <ValuePayButton
265
- publicKey="KP_xxx"
266
- amount={2000}
267
- customer={{ email: "user@example.com", fullName: "User" }}
268
- customization={{
269
- title: "My Store",
270
- description: "Thanks for shopping with us!",
271
- logoUrl: "https://mystore.com/logo.png",
272
- }}
273
- onSuccess={(res) => console.log(res)}
274
- />
275
- ```
276
-
277
- ---
278
-
279
- ## Server-Side Verification
280
-
281
- **Always verify transactions on your server.** Never trust client-side callbacks alone. Use the `ref` from the response:
282
-
283
- ```ts
284
- // Backend (Node.js example)
285
- const response = await fetch(
286
- "https://api.valuepayng.com/v1/transactions/verify",
287
- {
288
- method: "POST",
289
- headers: {
290
- "Content-Type": "application/json",
291
- Authorization: `Bearer ${VALUEPAY_SECRET_KEY}`,
292
- },
293
- body: JSON.stringify({ tx_ref: transactionRef }),
294
- },
295
- );
296
- const result = await response.json();
297
- ```
298
-
299
- ---
300
-
301
- ## TypeScript
302
-
303
- All types are exported:
304
-
305
- ```ts
306
- import type {
307
- ValuePayConfig,
308
- ValuePayResponse,
309
- ValuePayCustomer,
310
- ValuePayCustomization,
311
- PaymentChannel,
312
- ValuePayStatus,
313
- UseValuePayReturn,
314
- ValuePayButtonProps,
315
- ValuePayProviderProps,
316
- ValuePayProviderRef,
317
- } from "@valuepay/react";
318
- ```
319
-
320
- ---
321
-
322
- ## Browser Support
323
-
324
- | Browser | Minimum Version | Release Year |
325
- | -------------------- | --------------- | ------------ |
326
- | Chrome | 49+ | 2016 |
327
- | Firefox | 52+ | 2017 |
328
- | Safari | 10+ | 2016 |
329
- | Edge | 15+ | 2017 |
330
- | Opera | 36+ | 2016 |
331
- | Samsung Internet | 5.0+ | 2016 |
332
- | iOS Safari | 10+ | 2016 |
333
- | Android WebView | 49+ | 2016 |
334
- | Internet Explorer | 11 (with polyfills) | 2013 |
335
-
336
- The SDK targets **ES2018** and uses only features available in browsers from 2013 onwards (with appropriate polyfills for IE11). React 16.8+ is required for hooks support.
337
-
338
- ### SSR Compatibility
339
-
340
- The SDK is SSR-safe and works with:
341
- - Next.js (Pages Router and App Router)
342
- - Remix
343
- - Gatsby
344
- - Any server-side rendering framework
345
-
346
- All DOM access is guarded with `typeof document !== "undefined"` and `typeof window !== "undefined"` checks.
347
-
348
- ---
349
-
350
- ## Security
351
-
352
- - **Never** expose your secret key in client-side code. Only use your **public key** with this SDK.
353
- - **Always** verify transactions server-side before fulfilling orders — client-side callbacks can be spoofed.
354
- - **Use HTTPS** in production to prevent man-in-the-middle attacks.
355
- - **Generate unique transaction references** per payment to prevent duplicate charges.
356
- - The SDK loads the ValuePay checkout script from `https://www.valuepayng.com` — ensure this domain is allowed in your Content Security Policy (CSP).
357
- - The SDK does **not** store, log, or transmit any sensitive payment data (card numbers, CVV, etc.). All payment processing happens within the ValuePay checkout modal.
358
- - Transaction references are generated using cryptographically sufficient randomness via `Math.random()` with alphanumeric characters.
359
-
360
- ### Content Security Policy (CSP)
361
-
362
- If your application uses a Content Security Policy, add the following directives:
363
-
364
- ```
365
- script-src 'self' https://www.valuepayng.com;
366
- frame-src 'self' https://www.valuepayng.com;
367
- ```
368
-
369
- ---
370
-
371
- ## Error Handling
372
-
373
- The SDK provides an `onError` callback for handling SDK-level errors:
374
-
375
- ```tsx
376
- <ValuePayButton
377
- publicKey="KP_xxx"
378
- amount={5000}
379
- customer={{ email: "user@example.com", fullName: "User" }}
380
- onError={(error) => {
381
- console.error("Payment SDK error:", error.message);
382
- // Handle error — e.g., show a toast notification
383
- }}
384
- onSuccess={(res) => console.log(res)}
385
- />
386
- ```
387
-
388
- Common error scenarios:
389
- - ValuePay script failed to load (network issue, blocked by CSP)
390
- - `window.ValuepayCheckout` is not available
391
- - Invalid configuration
392
-
393
- ---
394
-
395
- ## Contributing
396
-
397
- We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
398
-
399
- ### Development Setup
400
-
401
- ```bash
402
- # Clone the repository
403
- git clone https://github.com/valuepayment/react-sdk.git
404
- cd react-sdk
405
-
406
- # Install dependencies
407
- npm install
408
-
409
- # Run tests
410
- npm test
411
-
412
- # Run tests in watch mode
413
- npm run test:watch
414
-
415
- # Lint
416
- npm run lint
417
-
418
- # Type check
419
- npm run typecheck
420
-
421
- # Build
422
- npm run build
423
- ```
424
-
425
- ---
426
-
427
- ## Changelog
428
-
429
- See [CHANGELOG.md](CHANGELOG.md) for a list of changes in each release.
430
-
431
- ---
432
-
433
- ## License
434
-
435
- MIT (c) [Value Payment Solutions Limited](https://valuepayng.com)
1
+ # @valuepay/react
2
+
3
+ > Official React SDK for [ValuePay](https://valuepayng.com) — accept payments in your React app with minimal setup.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@valuepay/react.svg)](https://www.npmjs.com/package/@valuepay/react)
6
+ [![license](https://img.shields.io/npm/l/@valuepay/react.svg)](LICENSE)
7
+ [![coverage](https://img.shields.io/badge/coverage-90%25-brightgreen.svg)]()
8
+ [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)]()
9
+
10
+ ---
11
+
12
+ ## Table of Contents
13
+
14
+ - [Installation](#installation)
15
+ - [Quick Start](#quick-start)
16
+ - [Option 1: Drop-in Button](#option-1-drop-in-button-simplest)
17
+ - [Option 2: Hook (Full Control)](#option-2-hook-full-control)
18
+ - [Option 3: Provider with Ref](#option-3-provider-with-ref-hidden-component)
19
+ - [Redirect Mode](#redirect-mode)
20
+ - [API Reference](#api-reference)
21
+ - [useValuePay](#usevaluepayconfig-valuepayconfig-usevaluepayreturn)
22
+ - [ValuePayButton](#valuepaybutton--props)
23
+ - [ValuePayProvider](#valuepayprovider--props)
24
+ - [ValuePayConfig](#valuepayconfig)
25
+ - [ValuePayResponse](#valuepayresponse)
26
+ - [Dynamic Amounts](#dynamic-amounts)
27
+ - [Payment Channels](#payment-channels)
28
+ - [Customizing the Checkout Modal](#customizing-the-checkout-modal)
29
+ - [Server-Side Verification](#server-side-verification)
30
+ - [TypeScript](#typescript)
31
+ - [Browser Support](#browser-support)
32
+ - [Security](#security)
33
+ - [Contributing](#contributing)
34
+ - [License](#license)
35
+
36
+ ---
37
+
38
+ ## Installation
39
+
40
+ ```bash
41
+ npm install @valuepay/react
42
+ # or
43
+ yarn add @valuepay/react
44
+ # or
45
+ pnpm add @valuepay/react
46
+ ```
47
+
48
+ ### Requirements
49
+
50
+ - **React** `>=16.8.0` (hooks support required)
51
+ - **React DOM** `>=16.8.0`
52
+
53
+ ---
54
+
55
+ ## Quick Start
56
+
57
+ ### Option 1: Drop-in Button (Simplest)
58
+
59
+ ```tsx
60
+ import { ValuePayButton } from "@valuepay/react";
61
+
62
+ function Checkout() {
63
+ return (
64
+ <ValuePayButton
65
+ publicKey="KP_your_public_key"
66
+ amount={5000}
67
+ customer={{ email: "jane@example.com", fullName: "Jane Doe" }}
68
+ onSuccess={(response) => {
69
+ console.log("Payment successful!", response.ref, response.status);
70
+ }}
71
+ onClose={(response) => {
72
+ console.log("Checkout closed", response);
73
+ }}
74
+ onCancelled={(response) => {
75
+ console.log("Payment cancelled", response);
76
+ }}
77
+ />
78
+ );
79
+ }
80
+ ```
81
+
82
+ The button renders as **"Pay ₦5,000 Now"** by default. Customize with `text`, `className`, `style`, or pass `children`.
83
+
84
+ ### Option 2: Hook (Full Control)
85
+
86
+ ```tsx
87
+ import { useValuePay } from "@valuepay/react";
88
+
89
+ function Checkout() {
90
+ const { initialize, isReady, isProcessing } = useValuePay({
91
+ publicKey: "KP_your_public_key",
92
+ amount: 10000,
93
+ customer: { email: "john@example.com", fullName: "John Doe" },
94
+ onSuccess: (response) => {
95
+ console.log("Paid!", response);
96
+ // response.ref, response.status, response.amount, etc.
97
+ },
98
+ onCancelled: (response) => console.log("Cancelled", response),
99
+ onClose: (response) => console.log("Closed", response),
100
+ });
101
+
102
+ return (
103
+ <button onClick={() => initialize()} disabled={!isReady || isProcessing}>
104
+ {isProcessing ? "Processing..." : "Pay ₦10,000"}
105
+ </button>
106
+ );
107
+ }
108
+ ```
109
+
110
+ ### Option 3: Provider with Ref (Hidden Component)
111
+
112
+ ```tsx
113
+ import { useRef } from "react";
114
+ import { ValuePayProvider, ValuePayProviderRef } from "@valuepay/react";
115
+
116
+ function Checkout() {
117
+ const payRef = useRef<ValuePayProviderRef>(null);
118
+
119
+ const handlePay = () => {
120
+ payRef.current?.initialize();
121
+ };
122
+
123
+ return (
124
+ <>
125
+ <ValuePayProvider
126
+ ref={payRef}
127
+ config={{
128
+ publicKey: "KP_your_public_key",
129
+ amount: 7500,
130
+ customer: { email: "alice@example.com", fullName: "Alice Smith" },
131
+ onSuccess: (response) => console.log("Success!", response),
132
+ onCancelled: (response) => console.log("Cancelled", response),
133
+ }}
134
+ />
135
+ <button onClick={handlePay}>Checkout</button>
136
+ </>
137
+ );
138
+ }
139
+ ```
140
+
141
+ ---
142
+
143
+ ## Redirect Mode
144
+
145
+ Instead of callbacks, you can redirect the user after payment:
146
+
147
+ ```tsx
148
+ <ValuePayButton
149
+ publicKey="KP_your_public_key"
150
+ amount={5000}
151
+ customer={{ email: "jane@example.com", fullName: "Jane Doe" }}
152
+ redirectUrl="https://yoursite.com/payment/verify"
153
+ />
154
+ ```
155
+
156
+ After payment, the user is redirected to:
157
+
158
+ ```
159
+ https://yoursite.com/payment/verify?ref=VPS_TX_abc123&status=SUCCESS
160
+ ```
161
+
162
+ Your server should then verify the transaction using the `ref` query parameter via the [ValuePay Verify API](https://developer.valuepayng.com/docs).
163
+
164
+ > **Important — Callback Precedence:** If you provide **any** callback (`onSuccess`, `onCallback`, `onCancelled`, `onClose`, or `onError`) alongside `redirectUrl`, the callbacks will take precedence and the redirect will **not** fire. `redirectUrl` is only used as a fallback when no callbacks are defined. This lets you safely set a `redirectUrl` as a backup while still handling events in-app when callbacks are present.
165
+
166
+ ---
167
+
168
+ ## `onSuccess` vs `onCallback`
169
+
170
+ These two callbacks serve different purposes — **use one or the other, not both**:
171
+
172
+ | Callback | Fires when | Use case |
173
+ |---|---|---|
174
+ | `onSuccess` | Payment succeeds (`SUCCESS` or `COMPLETED`) | You only care about successful payments |
175
+ | `onCallback` | **Every** payment event (success, failure, pending, etc.) | You want to handle all outcomes yourself |
176
+
177
+ ```tsx
178
+ // Option A: Use onSuccess for success-only handling
179
+ <ValuePayButton
180
+ publicKey="KP_xxx"
181
+ amount={5000}
182
+ customer={customer}
183
+ onSuccess={(res) => console.log("Paid!", res)}
184
+ onCancelled={(res) => console.log("Cancelled", res)}
185
+ onClose={(res) => console.log("Closed", res)}
186
+ />
187
+
188
+ // Option B: Use onCallback for all-events handling
189
+ <ValuePayButton
190
+ publicKey="KP_xxx"
191
+ amount={5000}
192
+ customer={customer}
193
+ onCallback={(res) => {
194
+ console.log("Event:", res.status, res);
195
+ // Handle SUCCESS, FAILED, PENDING, etc. yourself
196
+ }}
197
+ onCancelled={(res) => console.log("Cancelled", res)}
198
+ onClose={(res) => console.log("Closed", res)}
199
+ />
200
+ ```
201
+
202
+ > **Note:** `onCancelled`, `onClose`, and `onError` work alongside either choice they handle separate events (user cancellation, modal close, SDK errors).
203
+
204
+ ---
205
+
206
+ ## API Reference
207
+
208
+ ### `useValuePay(config: ValuePayConfig): UseValuePayReturn`
209
+
210
+ | Return | Type | Description |
211
+ | -------------- | ----------------------- | -------------------------------------------- |
212
+ | `initialize` | `(overrides?) => void` | Opens the ValuePay checkout modal |
213
+ | `isReady` | `boolean` | `true` when the ValuePay script has loaded |
214
+ | `isProcessing` | `boolean` | `true` while a payment is in progress |
215
+
216
+ ### `<ValuePayButton />` Props
217
+
218
+ Extends `ValuePayConfig` with:
219
+
220
+ | Prop | Type | Default | Description |
221
+ | -------------------- | ---------------- | ---------------------- | --------------------------------------------------------------------------- |
222
+ | `text` | `string` | `"Pay ₦{amount} Now"` | Button text |
223
+ | `className` | `string` | — | CSS class for the button element |
224
+ | `style` | `CSSProperties` | | Inline styles for the button (color, font, padding, etc.) |
225
+ | `containerStyle` | `CSSProperties` | — | Inline styles for the outer container (background, border, radius, size, margin, etc.) |
226
+ | `containerClassName` | `string` | | CSS class for the outer container div |
227
+ | `disabled` | `boolean` | `false` | Disable button |
228
+ | `children` | `ReactNode` | — | Custom button content |
229
+
230
+ > **Note:** All button props are optional. When `containerStyle` or `containerClassName` is provided, the button is wrapped in a `<div>` with those styles. Otherwise, no wrapper is rendered.
231
+
232
+ #### Styling Example
233
+
234
+ ```tsx
235
+ <ValuePayButton
236
+ publicKey="KP_xxx"
237
+ amount={5000}
238
+ customer={{ email: "user@example.com", fullName: "User" }}
239
+ containerStyle={{
240
+ width: "100%",
241
+ maxWidth: "400px",
242
+ margin: "20px auto",
243
+ borderRadius: "12px",
244
+ border: "1px solid #e0e0e0",
245
+ backgroundColor: "#f9f9f9",
246
+ padding: "16px",
247
+ }}
248
+ style={{
249
+ width: "100%",
250
+ color: "#fff",
251
+ backgroundColor: "#4CAF50",
252
+ fontSize: "16px",
253
+ padding: "12px 24px",
254
+ borderRadius: "8px",
255
+ border: "none",
256
+ cursor: "pointer",
257
+ }}
258
+ onSuccess={(res) => console.log(res)}
259
+ />
260
+ ```
261
+
262
+ ### `<ValuePayProvider />` Props
263
+
264
+ | Prop | Type | Description |
265
+ | -------- | ------------------------- | -------------------------------- |
266
+ | `config` | `ValuePayConfig` | Payment configuration |
267
+ | `ref` | `Ref<ValuePayProviderRef>`| Exposes `initialize()` method |
268
+
269
+ ### `ValuePayConfig`
270
+
271
+ | Prop | Type | Required | Default | Description |
272
+ | ---------------- | ---------------------------- | -------- | ------------------------------------ | ---------------------------------- |
273
+ | `publicKey` | `string` | Yes | — | Your ValuePay public key |
274
+ | `amount` | `number` | Yes | — | Amount in Naira |
275
+ | `customer` | `{ email, fullName, phone? }`| Yes | — | Customer details |
276
+ | `currency` | `string` | — | `"NGN"` | Currency code |
277
+ | `channels` | `PaymentChannel[]` | — | `["card","transfer","qrcode","ussd"]`| Enabled channels |
278
+ | `transactionRef` | `string` | — | Auto-generated | Custom transaction reference. `VPS_TX_` prefix auto-prepended if missing |
279
+ | `redirectUrl` | `string` | — | — | Fallback redirect URL (only used when no callbacks are provided) |
280
+ | `metaData` | `Record<string, unknown>` | — | — | Custom metadata |
281
+ | `customization` | `{ title?, description?, logoUrl? }` | | — | Checkout modal branding |
282
+ | `onSuccess` | `(response) => void` | — | — | Called on successful payment. Use this **or** `onCallback` — not both |
283
+ | `onClose` | `(response) => void` | — | — | Called when modal is closed |
284
+ | `onCancelled` | `(response) => void` | — | — | Called when payment is cancelled |
285
+ | `onCallback` | `(response) => void` | — | — | Called on **every** payment event. Use this **or** `onSuccess` — not both |
286
+ | `onError` | `(error) => void` | — | — | Called on SDK errors |
287
+ | `scriptUrl` | `string` | — | Production CDN | Override ValuePay script URL |
288
+
289
+ ### `ValuePayResponse`
290
+
291
+ | Field | Type | Description |
292
+ | ---------------- | ------------------ | --------------------------------------------------------------------------------------------- |
293
+ | `ref` | `string` | Transaction reference |
294
+ | `transactionRef` | `string` | Same as `ref` |
295
+ | `status` | `ValuePayStatus` | `"SUCCESS"`, `"COMPLETED"`, `"FAILED"`, `"CANCELLED"`, `"DUPLICATE"`, `"PENDING"` |
296
+ | `amount` | `number` | Transaction amount |
297
+ | `currency` | `string` | Currency code |
298
+ | `customer` | `ValuePayCustomer` | Customer details |
299
+ | `paymentMethod` | `string?` | Payment method used |
300
+ | `validation` | `{ status }?` | Server-side validation result |
301
+ | `raw` | `unknown?` | Raw ValuePay response |
302
+
303
+ ---
304
+
305
+ ## Dynamic Amounts
306
+
307
+ Override any config at call time:
308
+
309
+ ```tsx
310
+ const { initialize } = useValuePay({
311
+ publicKey: "KP_xxx",
312
+ amount: 0, // placeholder
313
+ customer: { email: "user@example.com", fullName: "User" },
314
+ onSuccess: (res) => console.log(res),
315
+ });
316
+
317
+ // Later, with dynamic amount:
318
+ initialize({ amount: selectedProduct.price });
319
+ ```
320
+
321
+ ---
322
+
323
+ ## Custom Transaction References
324
+
325
+ By default, a unique reference is auto-generated for every payment. If your business needs to control references (e.g. mapping to internal order IDs), pass your own `transactionRef`:
326
+
327
+ ```tsx
328
+ <ValuePayButton
329
+ publicKey="KP_xxx"
330
+ amount={5000}
331
+ customer={{ email: "user@example.com", fullName: "User" }}
332
+ transactionRef="ORDER_12345"
333
+ onSuccess={(res) => console.log(res.ref)} // → "VPS_TX_ORDER_12345"
334
+ />
335
+ ```
336
+
337
+ The `VPS_TX_` prefix is **always** prepended automatically. If your reference already includes the prefix, it won't be doubled:
338
+
339
+ ```tsx
340
+ transactionRef="VPS_TX_ORDER_12345" // stays "VPS_TX_ORDER_12345"
341
+ transactionRef="ORDER_12345" // becomes "VPS_TX_ORDER_12345"
342
+ ```
343
+
344
+ This also works with the hook and provider:
345
+
346
+ ```tsx
347
+ // Hook — set at config time
348
+ const { initialize } = useValuePay({
349
+ ...config,
350
+ transactionRef: "INV_9876",
351
+ });
352
+
353
+ // Or override at call time
354
+ initialize({ transactionRef: "INV_9876" });
355
+ ```
356
+
357
+ ---
358
+
359
+ ## Payment Channels
360
+
361
+ | Channel | Value |
362
+ | -------------- | ---------------- |
363
+ | Card | `"card"` |
364
+ | Bank Transfer | `"transfer"` |
365
+ | QR Code | `"qrcode"` |
366
+ | USSD | `"ussd"` |
367
+ | Mobile Money | `"mobile_money"` |
368
+
369
+ ---
370
+
371
+ ## Customizing the Checkout Modal
372
+
373
+ ```tsx
374
+ <ValuePayButton
375
+ publicKey="KP_xxx"
376
+ amount={2000}
377
+ customer={{ email: "user@example.com", fullName: "User" }}
378
+ customization={{
379
+ title: "My Store",
380
+ description: "Thanks for shopping with us!",
381
+ logoUrl: "https://mystore.com/logo.png",
382
+ }}
383
+ onSuccess={(res) => console.log(res)}
384
+ />
385
+ ```
386
+
387
+ ---
388
+
389
+ ## Server-Side Verification
390
+
391
+ **Always verify transactions on your server.** Never trust client-side callbacks alone. Use the `ref` from the response:
392
+
393
+ ```ts
394
+ // Backend (Node.js example)
395
+ const response = await fetch(
396
+ "https://api.valuepayng.com/v1/transactions/verify",
397
+ {
398
+ method: "POST",
399
+ headers: {
400
+ "Content-Type": "application/json",
401
+ Authorization: `Bearer ${VALUEPAY_SECRET_KEY}`,
402
+ },
403
+ body: JSON.stringify({ tx_ref: transactionRef }),
404
+ },
405
+ );
406
+ const result = await response.json();
407
+ ```
408
+
409
+ ---
410
+
411
+ ## TypeScript
412
+
413
+ All types are exported:
414
+
415
+ ```ts
416
+ import type {
417
+ ValuePayConfig,
418
+ ValuePayResponse,
419
+ ValuePayCustomer,
420
+ ValuePayCustomization,
421
+ PaymentChannel,
422
+ ValuePayStatus,
423
+ UseValuePayReturn,
424
+ ValuePayButtonProps,
425
+ ValuePayProviderProps,
426
+ ValuePayProviderRef,
427
+ } from "@valuepay/react";
428
+ ```
429
+
430
+ ---
431
+
432
+ ## Browser Support
433
+
434
+ | Browser | Minimum Version | Release Year |
435
+ | -------------------- | --------------- | ------------ |
436
+ | Chrome | 49+ | 2016 |
437
+ | Firefox | 52+ | 2017 |
438
+ | Safari | 10+ | 2016 |
439
+ | Edge | 15+ | 2017 |
440
+ | Opera | 36+ | 2016 |
441
+ | Samsung Internet | 5.0+ | 2016 |
442
+ | iOS Safari | 10+ | 2016 |
443
+ | Android WebView | 49+ | 2016 |
444
+ | Internet Explorer | 11 (with polyfills) | 2013 |
445
+
446
+ The SDK targets **ES2018** and uses only features available in browsers from 2013 onwards (with appropriate polyfills for IE11). React 16.8+ is required for hooks support.
447
+
448
+ ### SSR Compatibility
449
+
450
+ The SDK is SSR-safe and works with:
451
+ - Next.js (Pages Router and App Router)
452
+ - Remix
453
+ - Gatsby
454
+ - Any server-side rendering framework
455
+
456
+ All DOM access is guarded with `typeof document !== "undefined"` and `typeof window !== "undefined"` checks.
457
+
458
+ ---
459
+
460
+ ## Security
461
+
462
+ - **Never** expose your secret key in client-side code. Only use your **public key** with this SDK.
463
+ - **Always** verify transactions server-side before fulfilling orders — client-side callbacks can be spoofed.
464
+ - **Use HTTPS** in production to prevent man-in-the-middle attacks.
465
+ - **Generate unique transaction references** per payment to prevent duplicate charges.
466
+ - The SDK loads the ValuePay checkout script from `https://www.valuepayng.com` — ensure this domain is allowed in your Content Security Policy (CSP).
467
+ - The SDK does **not** store, log, or transmit any sensitive payment data (card numbers, CVV, etc.). All payment processing happens within the ValuePay checkout modal.
468
+ - Transaction references are generated using cryptographically sufficient randomness via `Math.random()` with alphanumeric characters.
469
+
470
+ ### Content Security Policy (CSP)
471
+
472
+ If your application uses a Content Security Policy, add the following directives:
473
+
474
+ ```
475
+ script-src 'self' https://www.valuepayng.com;
476
+ frame-src 'self' https://www.valuepayng.com;
477
+ ```
478
+
479
+ ---
480
+
481
+ ## Error Handling
482
+
483
+ The SDK provides an `onError` callback for handling SDK-level errors:
484
+
485
+ ```tsx
486
+ <ValuePayButton
487
+ publicKey="KP_xxx"
488
+ amount={5000}
489
+ customer={{ email: "user@example.com", fullName: "User" }}
490
+ onError={(error) => {
491
+ console.error("Payment SDK error:", error.message);
492
+ // Handle error — e.g., show a toast notification
493
+ }}
494
+ onSuccess={(res) => console.log(res)}
495
+ />
496
+ ```
497
+
498
+ Common error scenarios:
499
+ - ValuePay script failed to load (network issue, blocked by CSP)
500
+ - `window.ValuepayCheckout` is not available
501
+ - Invalid configuration
502
+
503
+ ---
504
+
505
+ ## Contributing
506
+
507
+ We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
508
+
509
+ ### Development Setup
510
+
511
+ ```bash
512
+ # Clone the repository
513
+ git clone https://github.com/valuepayment/react-sdk.git
514
+ cd react-sdk
515
+
516
+ # Install dependencies
517
+ npm install
518
+
519
+ # Run tests
520
+ npm test
521
+
522
+ # Run tests in watch mode
523
+ npm run test:watch
524
+
525
+ # Lint
526
+ npm run lint
527
+
528
+ # Type check
529
+ npm run typecheck
530
+
531
+ # Build
532
+ npm run build
533
+ ```
534
+
535
+ ---
536
+
537
+ ## Changelog
538
+
539
+ See [CHANGELOG.md](CHANGELOG.md) for a list of changes in each release.
540
+
541
+ ---
542
+
543
+ ## License
544
+
545
+ MIT (c) [Value Payment Solutions Limited](https://valuepayng.com)