@paypercut/checkout-js 1.0.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/LICENSE +22 -0
- package/README.md +569 -0
- package/dist/index.cjs +515 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +143 -0
- package/dist/index.mjs +509 -0
- package/dist/index.mjs.map +1 -0
- package/dist/paypercut-checkout-dev.iife.min.js +2 -0
- package/dist/paypercut-checkout-dev.iife.min.js.map +1 -0
- package/dist/paypercut-checkout.iife.min.js +2 -0
- package/dist/paypercut-checkout.iife.min.js.map +1 -0
- package/package.json +64 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Paypercut
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
package/README.md
ADDED
|
@@ -0,0 +1,569 @@
|
|
|
1
|
+
# Paypercut Checkout JavaScript SDK
|
|
2
|
+
|
|
3
|
+
A lightweight, framework-agnostic JavaScript SDK for embedding Paypercut Checkout into your web application. Works seamlessly with vanilla JavaScript, TypeScript, React, Vue, Angular, and other modern frameworks.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@paypercut/checkout-js)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
[](https://bundlephobia.com/package/@paypercut/checkout-js)
|
|
8
|
+
[](https://www.typescriptlang.org/)
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Table of Contents
|
|
13
|
+
|
|
14
|
+
- [Features](#features)
|
|
15
|
+
- [How It Works](#how-it-works)
|
|
16
|
+
- [Installation](#installation)
|
|
17
|
+
- [Quick Start](#quick-start)
|
|
18
|
+
- [API Reference](#api-reference)
|
|
19
|
+
- [Events](#events)
|
|
20
|
+
- [Usage Examples](#usage-examples)
|
|
21
|
+
- [Vanilla JavaScript](#vanilla-javascript-cdn)
|
|
22
|
+
- [TypeScript / ESM](#typescript--esm)
|
|
23
|
+
- [React](#react)
|
|
24
|
+
- [Security](#security)
|
|
25
|
+
- [Troubleshooting](#troubleshooting)
|
|
26
|
+
- [Performance Optimization](#performance-optimization)
|
|
27
|
+
- [Best Practices](#best-practices)
|
|
28
|
+
- [FAQ](#faq)
|
|
29
|
+
- [Support](#support)
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Installation
|
|
34
|
+
|
|
35
|
+
### Via NPM
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npm install @paypercut/checkout-js
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Via Yarn
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
yarn add @paypercut/checkout-js
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Via PNPM
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
pnpm add @paypercut/checkout-js
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Via CDN
|
|
54
|
+
|
|
55
|
+
```html
|
|
56
|
+
<!-- jsDelivr (recommended with SRI) -->
|
|
57
|
+
<script src="https://cdn.jsdelivr.net/npm/@paypercut/checkout-js@1.0.0/dist/paypercut-checkout.iife.min.js"
|
|
58
|
+
integrity="sha384-..."
|
|
59
|
+
crossorigin="anonymous"></script>
|
|
60
|
+
|
|
61
|
+
<!-- or UNPKG -->
|
|
62
|
+
<script src="https://unpkg.com/@paypercut/checkout-js@1.0.0/dist/paypercut-checkout.iife.min.js"></script>
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Quick Start
|
|
68
|
+
|
|
69
|
+
This returns a checkout session ID like `CHK_12345`.
|
|
70
|
+
|
|
71
|
+
### 1. Embed the Checkout
|
|
72
|
+
|
|
73
|
+
Use the checkout ID to initialize the checkout on your frontend:
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
import { PaypercutCheckout } from '@paypercut/checkout-js';
|
|
77
|
+
|
|
78
|
+
// Initialize the checkout
|
|
79
|
+
const checkout = PaypercutCheckout({
|
|
80
|
+
id: 'CHK_12345', // Your checkout session ID from step 1
|
|
81
|
+
containerId: '#checkout' // CSS selector or HTMLElement
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// Listen for payment events
|
|
85
|
+
checkout.on('success', () => {
|
|
86
|
+
console.log('Payment successful!');
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
checkout.on('error', () => {
|
|
90
|
+
console.error('Payment failed');
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// Optional: Listen for when iframe finishes loading (useful for modal implementations)
|
|
94
|
+
checkout.on('loaded', () => {
|
|
95
|
+
console.log('Checkout loaded and ready');
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// Render the checkout
|
|
99
|
+
checkout.render();
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
That's it! The checkout is now embedded in your page.
|
|
103
|
+
|
|
104
|
+
### 2. Display Mode
|
|
105
|
+
|
|
106
|
+
The SDK supports one display mode:
|
|
107
|
+
|
|
108
|
+
| Mode | When to Use | Configuration |
|
|
109
|
+
|------|-------------|---------------|
|
|
110
|
+
| **Embedded** | Checkout is part of your page layout | Provide `containerId` |
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## API Reference
|
|
114
|
+
|
|
115
|
+
### `PaypercutCheckout(options)`
|
|
116
|
+
|
|
117
|
+
Creates a new checkout instance.
|
|
118
|
+
|
|
119
|
+
#### Options
|
|
120
|
+
|
|
121
|
+
| Option | Type | Required | Description |
|
|
122
|
+
|--------|------|----------|-------------|
|
|
123
|
+
| `id` | `string` | Yes | Checkout session identifier |
|
|
124
|
+
| `containerId` | `string \| HTMLElement` | Yes | CSS selector or element where iframe mounts. |
|
|
125
|
+
|
|
126
|
+
#### Example
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
const checkout = PaypercutCheckout({
|
|
130
|
+
id: 'CHK_12345',
|
|
131
|
+
containerId: '#checkout-container'
|
|
132
|
+
});
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Instance Methods
|
|
136
|
+
|
|
137
|
+
#### `render()`
|
|
138
|
+
|
|
139
|
+
Mounts and displays the checkout iframe.
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
checkout.render();
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
#### `destroy()`
|
|
146
|
+
|
|
147
|
+
Destroys the instance and cleans up all event listeners. Call this when you're done with the checkout instance.
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
checkout.destroy();
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
#### `on(event, handler)`
|
|
154
|
+
|
|
155
|
+
Subscribes to checkout events. Returns an unsubscribe function.
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
const unsubscribe = checkout.on('success', () => {
|
|
159
|
+
console.log('Payment successful!');
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
// Later, to unsubscribe
|
|
163
|
+
unsubscribe();
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
#### `once(event, handler)`
|
|
167
|
+
|
|
168
|
+
Subscribes to a checkout event that automatically unsubscribes after the first emission. Returns an unsubscribe function.
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
checkout.once('loaded', () => {
|
|
172
|
+
console.log('Checkout loaded - this will only fire once');
|
|
173
|
+
});
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
#### `off(event, handler)`
|
|
177
|
+
|
|
178
|
+
Unsubscribes from checkout events.
|
|
179
|
+
|
|
180
|
+
```typescript
|
|
181
|
+
const handler = () => console.log('Payment successful!');
|
|
182
|
+
checkout.on('success', handler);
|
|
183
|
+
checkout.off('success', handler);
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
#### `isMounted()`
|
|
187
|
+
|
|
188
|
+
Returns whether the checkout is currently mounted.
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
if (checkout.isMounted()) {
|
|
192
|
+
console.log('Checkout is visible');
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## Events
|
|
199
|
+
|
|
200
|
+
Subscribe to events using the `on()` method:
|
|
201
|
+
|
|
202
|
+
| Event | Description | Payload |
|
|
203
|
+
|-------|-------------|---------|
|
|
204
|
+
| `loaded` | Checkout iframe has finished loading | `void` |
|
|
205
|
+
| `success` | Payment completed successfully | `void` |
|
|
206
|
+
| `error` | Payment failed or an error occurred | `void` |
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
## Usage Examples
|
|
210
|
+
|
|
211
|
+
### Vanilla JavaScript (CDN)
|
|
212
|
+
|
|
213
|
+
```html
|
|
214
|
+
<!DOCTYPE html>
|
|
215
|
+
<html>
|
|
216
|
+
<head>
|
|
217
|
+
<title>Paypercut Checkout</title>
|
|
218
|
+
</head>
|
|
219
|
+
<body>
|
|
220
|
+
<div id="checkout"></div>
|
|
221
|
+
|
|
222
|
+
<script src="https://cdn.jsdelivr.net/npm/@paypercut/checkout-js@1.0.0/dist/paypercut-checkout.iife.min.js"></script>
|
|
223
|
+
<script>
|
|
224
|
+
const checkout = PaypercutCheckout({
|
|
225
|
+
id: 'CHK_12345',
|
|
226
|
+
containerId: '#checkout'
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
checkout.on('success', function(data) {
|
|
230
|
+
alert('Payment successful! Transaction ID: ' + data.transactionId);
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
checkout.on('error', function(error) {
|
|
234
|
+
alert('Payment failed: ' + error.message);
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
checkout.render();
|
|
238
|
+
</script>
|
|
239
|
+
</body>
|
|
240
|
+
</html>
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### TypeScript / ESM
|
|
244
|
+
|
|
245
|
+
```typescript
|
|
246
|
+
import { PaypercutCheckout } from '@paypercut/checkout-js';
|
|
247
|
+
|
|
248
|
+
const checkout = PaypercutCheckout({
|
|
249
|
+
id: 'CHK_12345',
|
|
250
|
+
containerId: '#checkout'
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
checkout.on('success', (data) => {
|
|
254
|
+
console.log('Payment successful:', data);
|
|
255
|
+
// Redirect to success page
|
|
256
|
+
window.location.href = '/success';
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
checkout.on('error', (error) => {
|
|
260
|
+
console.error('Payment error:', error);
|
|
261
|
+
// Show error message to user
|
|
262
|
+
alert(`Payment failed: ${error.message}`);
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
checkout.render();
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### React
|
|
269
|
+
|
|
270
|
+
```tsx
|
|
271
|
+
import { useEffect, useRef, useState } from 'react';
|
|
272
|
+
import { PaypercutCheckout, CheckoutInstance } from '@paypercut/checkout-js';
|
|
273
|
+
|
|
274
|
+
export function CheckoutComponent({ checkoutId }: { checkoutId: string }) {
|
|
275
|
+
const containerRef = useRef<HTMLDivElement>(null);
|
|
276
|
+
const checkoutRef = useRef<CheckoutInstance | null>(null);
|
|
277
|
+
const [status, setStatus] = useState<'idle' | 'loading' | 'success' | 'error'>('idle');
|
|
278
|
+
|
|
279
|
+
useEffect(() => {
|
|
280
|
+
if (!containerRef.current) return;
|
|
281
|
+
|
|
282
|
+
const checkout = PaypercutCheckout({
|
|
283
|
+
id: checkoutId,
|
|
284
|
+
containerId: containerRef.current
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
checkout.on('loaded', () => {
|
|
288
|
+
setStatus('idle');
|
|
289
|
+
console.log('Checkout loaded');
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
checkout.on('success', (data) => {
|
|
293
|
+
setStatus('success');
|
|
294
|
+
console.log('Payment successful:', data);
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
checkout.on('error', (error) => {
|
|
298
|
+
setStatus('error');
|
|
299
|
+
console.error('Payment error:', error);
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
checkout.render();
|
|
303
|
+
checkoutRef.current = checkout;
|
|
304
|
+
|
|
305
|
+
return () => {
|
|
306
|
+
checkout.destroy();
|
|
307
|
+
};
|
|
308
|
+
}, [checkoutId]);
|
|
309
|
+
|
|
310
|
+
return (
|
|
311
|
+
<div>
|
|
312
|
+
<div ref={containerRef} style={{ width: '100%', height: '600px' }} />
|
|
313
|
+
{status === 'loading' && <p>Processing payment...</p>}
|
|
314
|
+
{status === 'success' && <p>✅ Payment successful!</p>}
|
|
315
|
+
{status === 'error' && <p>❌ Payment failed. Please try again.</p>}
|
|
316
|
+
</div>
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
### Modal-like Implementation
|
|
322
|
+
|
|
323
|
+
If you want to create a modal-like experience, you can use the `loaded` event to show/hide a loading overlay:
|
|
324
|
+
|
|
325
|
+
```tsx
|
|
326
|
+
import { useEffect, useRef, useState } from 'react';
|
|
327
|
+
import { PaypercutCheckout, CheckoutInstance } from '@paypercut/checkout-js';
|
|
328
|
+
|
|
329
|
+
export function ModalCheckout({ checkoutId, onClose }: { checkoutId: string; onClose: () => void }) {
|
|
330
|
+
const containerRef = useRef<HTMLDivElement>(null);
|
|
331
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
332
|
+
|
|
333
|
+
useEffect(() => {
|
|
334
|
+
if (!containerRef.current) return;
|
|
335
|
+
|
|
336
|
+
const checkout = PaypercutCheckout({
|
|
337
|
+
id: checkoutId,
|
|
338
|
+
containerId: containerRef.current
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
checkout.on('loaded', () => {
|
|
342
|
+
setIsLoading(false);
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
checkout.on('success', (data) => {
|
|
346
|
+
console.log('Payment successful:', data);
|
|
347
|
+
onClose();
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
checkout.on('error', (error) => {
|
|
351
|
+
console.error('Payment error:', error);
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
checkout.render();
|
|
355
|
+
|
|
356
|
+
return () => {
|
|
357
|
+
checkout.destroy();
|
|
358
|
+
};
|
|
359
|
+
}, [checkoutId, onClose]);
|
|
360
|
+
|
|
361
|
+
return (
|
|
362
|
+
<div style={{
|
|
363
|
+
position: 'fixed',
|
|
364
|
+
top: 0,
|
|
365
|
+
left: 0,
|
|
366
|
+
right: 0,
|
|
367
|
+
bottom: 0,
|
|
368
|
+
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
|
369
|
+
display: 'flex',
|
|
370
|
+
alignItems: 'center',
|
|
371
|
+
justifyContent: 'center',
|
|
372
|
+
zIndex: 9999
|
|
373
|
+
}}>
|
|
374
|
+
<div style={{
|
|
375
|
+
position: 'relative',
|
|
376
|
+
width: '90%',
|
|
377
|
+
maxWidth: '500px',
|
|
378
|
+
height: '90%',
|
|
379
|
+
maxHeight: '700px',
|
|
380
|
+
backgroundColor: '#fff',
|
|
381
|
+
borderRadius: '12px',
|
|
382
|
+
overflow: 'hidden'
|
|
383
|
+
}}>
|
|
384
|
+
{isLoading && (
|
|
385
|
+
<div style={{
|
|
386
|
+
position: 'absolute',
|
|
387
|
+
top: 0,
|
|
388
|
+
left: 0,
|
|
389
|
+
right: 0,
|
|
390
|
+
bottom: 0,
|
|
391
|
+
display: 'flex',
|
|
392
|
+
alignItems: 'center',
|
|
393
|
+
justifyContent: 'center',
|
|
394
|
+
backgroundColor: '#fff',
|
|
395
|
+
zIndex: 1
|
|
396
|
+
}}>
|
|
397
|
+
<p>Loading checkout...</p>
|
|
398
|
+
</div>
|
|
399
|
+
)}
|
|
400
|
+
<div ref={containerRef} style={{ width: '100%', height: '100%' }} />
|
|
401
|
+
<button
|
|
402
|
+
onClick={onClose}
|
|
403
|
+
style={{
|
|
404
|
+
position: 'absolute',
|
|
405
|
+
top: '10px',
|
|
406
|
+
right: '10px',
|
|
407
|
+
zIndex: 2
|
|
408
|
+
}}
|
|
409
|
+
>
|
|
410
|
+
✕
|
|
411
|
+
</button>
|
|
412
|
+
</div>
|
|
413
|
+
</div>
|
|
414
|
+
);
|
|
415
|
+
}
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
## Security
|
|
419
|
+
|
|
420
|
+
### Origin Validation
|
|
421
|
+
|
|
422
|
+
The SDK automatically validates all postMessage communications against the configured `checkoutHost` origin. This prevents unauthorized messages from being processed.
|
|
423
|
+
|
|
424
|
+
### Content Security Policy
|
|
425
|
+
|
|
426
|
+
For enhanced security, configure your Content Security Policy headers:
|
|
427
|
+
|
|
428
|
+
```
|
|
429
|
+
Content-Security-Policy:
|
|
430
|
+
frame-src https://buy.paypercut.io OR something else;
|
|
431
|
+
script-src 'self' https://cdn.jsdelivr.net https://unpkg.com;
|
|
432
|
+
connect-src https://buy.paypercut.io OR something else;
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
### HTTPS Only
|
|
436
|
+
|
|
437
|
+
Always use HTTPS in production. The SDK is designed for secure communication over HTTPS.
|
|
438
|
+
|
|
439
|
+
## Troubleshooting
|
|
440
|
+
|
|
441
|
+
### Checkout not displaying
|
|
442
|
+
|
|
443
|
+
**Problem:** The iframe doesn't appear after calling `render()`.
|
|
444
|
+
|
|
445
|
+
**Solutions:**
|
|
446
|
+
- Ensure the container element exists in the DOM before calling `render()`
|
|
447
|
+
- Check that the `id` is a valid checkout session ID
|
|
448
|
+
- Verify there are no CSP errors in the browser console
|
|
449
|
+
- Enable debug mode: `debug: true` to see detailed logs
|
|
450
|
+
|
|
451
|
+
### Events not firing
|
|
452
|
+
|
|
453
|
+
**Problem:** Event handlers are not being called.
|
|
454
|
+
|
|
455
|
+
**Solutions:**
|
|
456
|
+
- Ensure you subscribe to events before calling `render()`
|
|
457
|
+
- Check that the checkout session is active and not expired
|
|
458
|
+
- Enable debug mode to see message logs
|
|
459
|
+
|
|
460
|
+
### TypeScript errors
|
|
461
|
+
|
|
462
|
+
**Problem:** TypeScript shows type errors when using the SDK.
|
|
463
|
+
|
|
464
|
+
**Solutions:**
|
|
465
|
+
- Ensure you're importing types: `import { PaypercutCheckout, CheckoutInstance } from '@paypercut/checkout-js'`
|
|
466
|
+
- Update to the latest version of the SDK
|
|
467
|
+
- Check that your `tsconfig.json` includes the SDK's type definitions
|
|
468
|
+
|
|
469
|
+
## Performance Optimization
|
|
470
|
+
|
|
471
|
+
### Preconnect to Checkout Host
|
|
472
|
+
|
|
473
|
+
Add DNS prefetch and preconnect hints to your HTML for faster loading:
|
|
474
|
+
|
|
475
|
+
```html
|
|
476
|
+
<link rel="preconnect" href="https://buy.paypercut.io ">
|
|
477
|
+
<link rel="dns-prefetch" href="https://buy.paypercut.io ">
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
### Lazy Loading
|
|
481
|
+
|
|
482
|
+
Load the SDK only when needed to reduce initial bundle size:
|
|
483
|
+
|
|
484
|
+
```typescript
|
|
485
|
+
async function loadCheckout() {
|
|
486
|
+
const { PaypercutCheckout } = await import('@paypercut/checkout-js');
|
|
487
|
+
return PaypercutCheckout;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// Load when user clicks pay button
|
|
491
|
+
payButton.addEventListener('click', async () => {
|
|
492
|
+
const PaypercutCheckout = await loadCheckout();
|
|
493
|
+
const checkout = PaypercutCheckout({ id: 'CHK_12345' });
|
|
494
|
+
checkout.render();
|
|
495
|
+
});
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
---
|
|
499
|
+
|
|
500
|
+
## Best Practices
|
|
501
|
+
|
|
502
|
+
### 1. Always Verify Payments on Your Backend
|
|
503
|
+
|
|
504
|
+
Never rely solely on frontend events for payment confirmation. Always verify payments using webhooks on your backend:
|
|
505
|
+
|
|
506
|
+
```typescript
|
|
507
|
+
// ✅ Good: Use frontend events for UI updates only
|
|
508
|
+
checkout.on('success', () => {
|
|
509
|
+
// Show success message
|
|
510
|
+
showSuccessMessage();
|
|
511
|
+
// Redirect to order confirmation page
|
|
512
|
+
window.location.href = '/orders/confirmation';
|
|
513
|
+
});
|
|
514
|
+
|
|
515
|
+
// ❌ Bad: Don't grant access based on frontend events alone
|
|
516
|
+
checkout.on('success', () => {
|
|
517
|
+
// This can be manipulated by users!
|
|
518
|
+
grantPremiumAccess(userId); // Don't do this!
|
|
519
|
+
});
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
### 2. Handle All Event Types
|
|
523
|
+
|
|
524
|
+
Always handle both success and error events:
|
|
525
|
+
|
|
526
|
+
```typescript
|
|
527
|
+
checkout.on('success', () => {
|
|
528
|
+
// Handle success
|
|
529
|
+
showSuccessMessage();
|
|
530
|
+
});
|
|
531
|
+
|
|
532
|
+
checkout.on('error', () => {
|
|
533
|
+
// Show user-friendly error message
|
|
534
|
+
alert('Payment failed. Please try again.');
|
|
535
|
+
});
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
### 3. Clean Up on Component Unmount
|
|
539
|
+
|
|
540
|
+
Always call `destroy()` when your component unmounts to prevent memory leaks:
|
|
541
|
+
|
|
542
|
+
```typescript
|
|
543
|
+
// React example
|
|
544
|
+
useEffect(() => {
|
|
545
|
+
const checkout = PaypercutCheckout({ id: checkoutId });
|
|
546
|
+
checkout.render();
|
|
547
|
+
|
|
548
|
+
return () => {
|
|
549
|
+
checkout.destroy(); // Clean up!
|
|
550
|
+
};
|
|
551
|
+
}, []);
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
## FAQ For Internal Validation
|
|
555
|
+
|
|
556
|
+
**Q: How do I handle successful payments?**
|
|
557
|
+
Listen to the `success` event and redirect users or update your UI accordingly. Always verify the payment on your backend using webhooks.
|
|
558
|
+
|
|
559
|
+
**Q: Can I use this with server-side rendering (SSR)?**
|
|
560
|
+
Yes, but ensure the SDK is only initialized on the client side. For Next.js, use dynamic imports with `ssr: false`.
|
|
561
|
+
|
|
562
|
+
**Q: What happens if the user closes the browser during payment?**
|
|
563
|
+
|
|
564
|
+
**Q: Can I have multiple checkouts on one page?**
|
|
565
|
+
Maybe Yes, but only one should be active at a time to avoid user confusion.
|
|
566
|
+
If no, we destroy the previous one and create a new one.
|
|
567
|
+
|
|
568
|
+
**Q: How do I handle errors?**
|
|
569
|
+
Listen to the `error` event and display user-friendly error messages. Log errors for debugging.
|