@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 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
+ [![npm version](https://img.shields.io/npm/v/@paypercut/checkout-js.svg)](https://www.npmjs.com/package/@paypercut/checkout-js)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
7
+ [![Bundle Size](https://img.shields.io/bundlephobia/minzip/@paypercut/checkout-js)](https://bundlephobia.com/package/@paypercut/checkout-js)
8
+ [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](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.