@one-payments/web-components 1.1.27 → 1.1.29

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.
@@ -0,0 +1,980 @@
1
+ # CDN Integration Guide
2
+
3
+ ## Overview
4
+
5
+ This guide explains how to integrate the ONE Payments Drop-in Element on platforms that don't use npm or bundlers, such as **Shopify**, **Wix**, and **WordPress**.
6
+
7
+ The `@one-payments/web-components` package provides a browser-ready IIFE bundle that can be loaded via a simple `<script>` tag:
8
+
9
+ ```html
10
+ <script src="https://cdn.jsdelivr.net/npm/@one-payments/web-components@1.1.28/dist/one-payment.browser.iife.js"></script>
11
+ ```
12
+
13
+ This bundle:
14
+ - Auto-registers the `<one-payment>` custom element
15
+ - Exposes a global `window.OnePayments` API
16
+ - Bundles all dependencies (no additional scripts needed)
17
+ - Works without npm, bundlers, or build steps
18
+
19
+ ---
20
+
21
+ ## CRITICAL: orderId Must Be a UUID
22
+
23
+ > **This is the most important requirement. Read this section carefully.**
24
+
25
+ The backend **strictly validates** the `orderId` format. If `orderId` is not a valid UUID, the payment request **will fail**.
26
+
27
+ ### What is Required
28
+
29
+ `orderId` must be a **pure UUID string** with no prefixes, suffixes, or additional data.
30
+
31
+ **Correct format (UUID v4):**
32
+ ```
33
+ 550e8400-e29b-41d4-a716-446655440000
34
+ ```
35
+
36
+ ### Examples
37
+
38
+ | Example | Valid? | Reason |
39
+ |---------|--------|--------|
40
+ | `550e8400-e29b-41d4-a716-446655440000` | ✅ Yes | Pure UUID |
41
+ | `cart-550e8400-e29b-41d4-a716-446655440000` | ❌ No | Has prefix |
42
+ | `550e8400-e29b-41d4-a716-446655440000__cartToken` | ❌ No | Has suffix |
43
+ | `550e8400-e29b-41d4-a716-446655440000-12345` | ❌ No | Extra data appended |
44
+ | `order-123` | ❌ No | Not a UUID |
45
+ | `12345` | ❌ No | Not a UUID |
46
+ | `{{ cart.token }}` (Shopify) | ❌ No | Cart token is not a UUID |
47
+
48
+ ### How to Generate a UUID
49
+
50
+ Use the built-in browser API:
51
+
52
+ ```javascript
53
+ const orderId = crypto.randomUUID();
54
+ // Result: "550e8400-e29b-41d4-a716-446655440000"
55
+ ```
56
+
57
+ `crypto.randomUUID()` is supported in all modern browsers (Chrome 92+, Firefox 95+, Safari 15.4+, Edge 92+).
58
+
59
+ ### Common Mistakes to Avoid
60
+
61
+ | Mistake | Why It's Wrong |
62
+ |---------|----------------|
63
+ | Using Shopify `cart.token` as orderId | Cart token is not a UUID format |
64
+ | Concatenating UUID with cart.token | Backend expects pure UUID only |
65
+ | Using order numbers like `#1001` | Not a UUID format |
66
+ | Reusing the same orderId for multiple payments | Each payment attempt needs a fresh UUID |
67
+
68
+ ---
69
+
70
+ ## General Usage Pattern
71
+
72
+ This pattern works on **any platform** that supports `<script>` tags:
73
+
74
+ ```html
75
+ <!-- 1. Load the CDN bundle -->
76
+ <script src="https://cdn.jsdelivr.net/npm/@one-payments/web-components@1.1.28/dist/one-payment.browser.iife.js"></script>
77
+
78
+ <!-- 2. Place the web component -->
79
+ <one-payment id="one-payment-element"></one-payment>
80
+
81
+ <!-- 3. Configure via JavaScript -->
82
+ <script>
83
+ var el = document.getElementById('one-payment-element');
84
+
85
+ // Amount in minor units (e.g., cents)
86
+ // 5000 = $50.00 USD
87
+ el.amount = 5000;
88
+
89
+ // ISO 4217 currency code
90
+ el.currency = 'USD';
91
+
92
+ // ✅ CRITICAL: Generate a fresh UUID for each payment
93
+ el.orderId = crypto.randomUUID();
94
+
95
+ // Configuration
96
+ el.config = {
97
+ apiKey: 'pk_live_...', // Your public API key
98
+ secretKey: 'sk_live_...', // Your secret key
99
+ environment: 'prod' // 'prod' or 'demo'
100
+ };
101
+
102
+ // Create browser adapters
103
+ el.adapters = OnePayments.createWebAdapters();
104
+
105
+ // Customer information
106
+ el.firstName = 'John';
107
+ el.lastName = 'Doe';
108
+ el.email = 'john@example.com';
109
+
110
+ // Handle successful payment
111
+ el.addEventListener('payment-success', function(event) {
112
+ console.log('Payment successful!', event.detail.paymentIntentId);
113
+ // Redirect to success page or update UI
114
+ });
115
+
116
+ // Handle payment error
117
+ el.addEventListener('payment-error', function(event) {
118
+ console.error('Payment failed:', event.detail.error);
119
+ // Show error message to user
120
+ });
121
+ </script>
122
+ ```
123
+
124
+ ### Required Properties
125
+
126
+ | Property | Type | Description |
127
+ |----------|------|-------------|
128
+ | `amount` | Number | Amount in minor units (cents). Example: `5000` = $50.00 |
129
+ | `currency` | String | ISO 4217 currency code. Example: `'USD'`, `'SGD'`, `'EUR'` |
130
+ | `orderId` | String | **Must be a UUID.** Use `crypto.randomUUID()` |
131
+ | `config` | Object | Contains `apiKey`, `secretKey`, `environment` |
132
+ | `adapters` | Object | Use `OnePayments.createWebAdapters()` |
133
+
134
+ ### Optional Properties
135
+
136
+ | Property | Type | Description |
137
+ |----------|------|-------------|
138
+ | `firstName` | String | Customer's first name |
139
+ | `lastName` | String | Customer's last name |
140
+ | `email` | String | Customer's email address |
141
+
142
+ ### Events
143
+
144
+ | Event | Description |
145
+ |-------|-------------|
146
+ | `payment-success` | Fired when payment completes successfully. `event.detail.paymentIntentId` contains the payment ID. |
147
+ | `payment-error` | Fired when payment fails. `event.detail.error` contains error information. |
148
+ | `state-change` | Fired when internal state changes. `event.detail.state` contains current state. |
149
+
150
+ ---
151
+
152
+ ## Shopify Integration
153
+
154
+ This section explains how to integrate the ONE Payments Drop-in Element into a Shopify theme.
155
+
156
+ ### Where to Add the Code
157
+
158
+ You can add this code to:
159
+ - `sections/cart-template.liquid` - For cart page integration
160
+ - `snippets/one-payments.liquid` - As a reusable snippet
161
+ - `templates/cart.liquid` - For older themes
162
+
163
+ ### Understanding Shopify Data
164
+
165
+ Shopify provides these Liquid variables:
166
+ - `{{ cart.total_price }}` - Cart total in minor units (cents)
167
+ - `{{ shop.currency }}` - Store currency code (e.g., "USD")
168
+ - `{{ customer.first_name }}` - Customer's first name (if logged in)
169
+ - `{{ customer.last_name }}` - Customer's last name (if logged in)
170
+ - `{{ customer.email }}` - Customer's email (if logged in)
171
+
172
+ > **Important:** Do NOT use `{{ cart.token }}` as orderId. Cart token is not a UUID.
173
+
174
+ ### Complete Shopify Example
175
+
176
+ Create a new file `snippets/one-payments-dropin.liquid`:
177
+
178
+ ```liquid
179
+ {% comment %}
180
+ ONE Payments Drop-in Element
181
+
182
+ Usage: {% render 'one-payments-dropin' %}
183
+
184
+ IMPORTANT: orderId must be a UUID generated via crypto.randomUUID()
185
+ Do NOT use cart.token as orderId - it will fail backend validation.
186
+ {% endcomment %}
187
+
188
+ <div id="one-payments-container" style="max-width: 500px; margin: 20px auto;">
189
+ <one-payment id="one-payment-element"></one-payment>
190
+ </div>
191
+
192
+ <!-- Load ONE Payments CDN Bundle -->
193
+ <script src="https://cdn.jsdelivr.net/npm/@one-payments/web-components@1.1.28/dist/one-payment.browser.iife.js"></script>
194
+
195
+ <script>
196
+ (function() {
197
+ // Wait for DOM to be ready
198
+ if (document.readyState === 'loading') {
199
+ document.addEventListener('DOMContentLoaded', initPayment);
200
+ } else {
201
+ initPayment();
202
+ }
203
+
204
+ function initPayment() {
205
+ var el = document.getElementById('one-payment-element');
206
+
207
+ if (!el) {
208
+ console.error('[ONE Payments] Payment element not found');
209
+ return;
210
+ }
211
+
212
+ // =====================================================
213
+ // AMOUNT & CURRENCY (from Shopify Liquid)
214
+ // =====================================================
215
+
216
+ // cart.total_price is in minor units (cents)
217
+ // Example: $50.00 = 5000
218
+ el.amount = {{ cart.total_price }};
219
+
220
+ // Shop currency (e.g., "USD", "SGD", "EUR")
221
+ el.currency = "{{ shop.currency }}";
222
+
223
+ // =====================================================
224
+ // ORDER ID - MUST BE A UUID
225
+ // =====================================================
226
+
227
+ // ✅ CORRECT: Generate a fresh UUID for each payment
228
+ el.orderId = crypto.randomUUID();
229
+
230
+ // ❌ WRONG: Do NOT use cart.token
231
+ // el.orderId = "{{ cart.token }}"; // This will FAIL!
232
+
233
+ // ❌ WRONG: Do NOT concatenate with other values
234
+ // el.orderId = crypto.randomUUID() + "__{{ cart.token }}"; // This will FAIL!
235
+
236
+ // =====================================================
237
+ // CONFIGURATION
238
+ // =====================================================
239
+
240
+ el.config = {
241
+ apiKey: 'pk_live_YOUR_API_KEY_HERE',
242
+ secretKey: 'sk_live_YOUR_SECRET_KEY_HERE',
243
+ environment: 'prod' // Use 'demo' for testing
244
+ };
245
+
246
+ // Create browser adapters
247
+ el.adapters = OnePayments.createWebAdapters();
248
+
249
+ // =====================================================
250
+ // CUSTOMER INFORMATION (optional but recommended)
251
+ // =====================================================
252
+
253
+ {% if customer %}
254
+ // Logged-in customer - use their saved information
255
+ el.firstName = {{ customer.first_name | json }};
256
+ el.lastName = {{ customer.last_name | json }};
257
+ el.email = {{ customer.email | json }};
258
+ {% else %}
259
+ // Guest checkout - you may want to collect this via a form
260
+ // or leave empty and let the payment form collect it
261
+ el.firstName = '';
262
+ el.lastName = '';
263
+ el.email = '';
264
+ {% endif %}
265
+
266
+ // =====================================================
267
+ // EVENT HANDLERS
268
+ // =====================================================
269
+
270
+ // Handle successful payment
271
+ el.addEventListener('payment-success', function(event) {
272
+ console.log('[ONE Payments] Payment successful!');
273
+ console.log('Payment Intent ID:', event.detail.paymentIntentId);
274
+
275
+ // Option 1: Redirect to thank you page
276
+ // window.location.href = '/pages/thank-you';
277
+
278
+ // Option 2: Redirect to Shopify checkout to complete order
279
+ // window.location.href = '/checkout';
280
+
281
+ // Option 3: Show success message
282
+ alert('Payment successful! Order ID: ' + event.detail.paymentIntentId);
283
+ });
284
+
285
+ // Handle payment error
286
+ el.addEventListener('payment-error', function(event) {
287
+ console.error('[ONE Payments] Payment failed:', event.detail.error);
288
+ alert('Payment failed: ' + event.detail.error);
289
+ });
290
+
291
+ // Optional: Handle state changes for loading indicators
292
+ el.addEventListener('state-change', function(event) {
293
+ var state = event.detail.state;
294
+ console.log('[ONE Payments] State changed to:', state.status);
295
+
296
+ // You can show/hide loading indicators here
297
+ // if (state.status === 'processing') { showLoading(); }
298
+ // if (state.status === 'ready') { hideLoading(); }
299
+ });
300
+
301
+ console.log('[ONE Payments] Payment element initialized');
302
+ console.log('Amount:', el.amount, 'cents');
303
+ console.log('Currency:', el.currency);
304
+ console.log('Order ID:', el.orderId);
305
+ }
306
+ })();
307
+ </script>
308
+ ```
309
+
310
+ ### Using the Snippet
311
+
312
+ In your cart template (`sections/cart-template.liquid` or similar), add:
313
+
314
+ ```liquid
315
+ {% render 'one-payments-dropin' %}
316
+ ```
317
+
318
+ ### Shopify-Specific Notes
319
+
320
+ | Topic | Details |
321
+ |-------|---------|
322
+ | **Amount format** | `cart.total_price` is already in minor units (cents). No conversion needed. |
323
+ | **Currency** | `shop.currency` gives the ISO code. Use it directly. |
324
+ | **Customer data** | Use `{% if customer %}` to check if user is logged in. |
325
+ | **Order ID** | Always use `crypto.randomUUID()`. Never use `cart.token`. |
326
+ | **Checkout flow** | After payment success, you may redirect to Shopify checkout or a custom thank-you page. |
327
+
328
+ ### Testing on Shopify
329
+
330
+ 1. Use `environment: 'demo'` for testing
331
+ 2. Use demo API keys (not production keys)
332
+ 3. Check browser console for any errors
333
+ 4. Verify the payment element renders correctly
334
+ 5. Test with a demo card number
335
+
336
+ ---
337
+
338
+ ## Wix Integration
339
+
340
+ This section explains how to integrate the ONE Payments Drop-in Element into a Wix site.
341
+
342
+ ### Integration Methods
343
+
344
+ Wix offers two ways to add custom code:
345
+
346
+ 1. **HTML Embed** - Simple, no coding required beyond the snippet
347
+ 2. **Velo (Wix Code)** - More advanced, allows dynamic data
348
+
349
+ ### Method 1: HTML Embed (Simple)
350
+
351
+ This is the easiest method for most Wix users.
352
+
353
+ #### Step 1: Add an HTML Embed Element
354
+
355
+ 1. In Wix Editor, click **Add** (+)
356
+ 2. Select **Embed** > **Custom Embeds** > **Embed a Widget**
357
+ 3. Click **Enter Code**
358
+
359
+ #### Step 2: Paste This Code
360
+
361
+ ```html
362
+ <!DOCTYPE html>
363
+ <html>
364
+ <head>
365
+ <meta charset="UTF-8">
366
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
367
+ <style>
368
+ * {
369
+ margin: 0;
370
+ padding: 0;
371
+ box-sizing: border-box;
372
+ }
373
+ body {
374
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
375
+ padding: 20px;
376
+ }
377
+ #payment-container {
378
+ max-width: 100%;
379
+ }
380
+ </style>
381
+ </head>
382
+ <body>
383
+ <div id="payment-container">
384
+ <one-payment id="payment"></one-payment>
385
+ </div>
386
+
387
+ <!-- Load ONE Payments CDN Bundle -->
388
+ <script src="https://cdn.jsdelivr.net/npm/@one-payments/web-components@1.1.28/dist/one-payment.browser.iife.js"></script>
389
+
390
+ <script>
391
+ (function() {
392
+ var el = document.getElementById('payment');
393
+
394
+ if (!el) {
395
+ console.error('[ONE Payments] Payment element not found');
396
+ return;
397
+ }
398
+
399
+ // =====================================================
400
+ // AMOUNT & CURRENCY
401
+ // =====================================================
402
+
403
+ // Set your amount in minor units (cents)
404
+ // Example: $50.00 = 5000
405
+ el.amount = 5000;
406
+
407
+ // Set your currency
408
+ el.currency = 'USD';
409
+
410
+ // =====================================================
411
+ // ORDER ID - MUST BE A UUID
412
+ // =====================================================
413
+
414
+ // ✅ CORRECT: Generate a fresh UUID
415
+ el.orderId = crypto.randomUUID();
416
+
417
+ // =====================================================
418
+ // CONFIGURATION
419
+ // =====================================================
420
+
421
+ el.config = {
422
+ apiKey: 'pk_live_YOUR_API_KEY_HERE',
423
+ secretKey: 'sk_live_YOUR_SECRET_KEY_HERE',
424
+ environment: 'prod' // Use 'demo' for testing
425
+ };
426
+
427
+ el.adapters = OnePayments.createWebAdapters();
428
+
429
+ // =====================================================
430
+ // CUSTOMER INFORMATION
431
+ // =====================================================
432
+
433
+ el.firstName = 'John';
434
+ el.lastName = 'Doe';
435
+ el.email = 'john@example.com';
436
+
437
+ // =====================================================
438
+ // EVENT HANDLERS
439
+ // =====================================================
440
+
441
+ // Handle successful payment
442
+ el.addEventListener('payment-success', function(event) {
443
+ console.log('Payment successful!', event.detail.paymentIntentId);
444
+
445
+ // Notify parent Wix page
446
+ window.parent.postMessage({
447
+ type: 'ONE_PAYMENT_SUCCESS',
448
+ paymentIntentId: event.detail.paymentIntentId
449
+ }, '*');
450
+ });
451
+
452
+ // Handle payment error
453
+ el.addEventListener('payment-error', function(event) {
454
+ console.error('Payment failed:', event.detail.error);
455
+
456
+ // Notify parent Wix page
457
+ window.parent.postMessage({
458
+ type: 'ONE_PAYMENT_ERROR',
459
+ error: event.detail.error
460
+ }, '*');
461
+ });
462
+
463
+ console.log('[ONE Payments] Initialized with Order ID:', el.orderId);
464
+ })();
465
+ </script>
466
+ </body>
467
+ </html>
468
+ ```
469
+
470
+ #### Step 3: Resize the Embed
471
+
472
+ - Set width to 100% or a fixed width like 500px
473
+ - Set height to approximately 600px (adjust as needed)
474
+
475
+ ### Method 2: Velo (Advanced)
476
+
477
+ If you need to pass dynamic data (like cart amount), use Velo page code.
478
+
479
+ #### HTML Embed (with URL parameters)
480
+
481
+ ```html
482
+ <!DOCTYPE html>
483
+ <html>
484
+ <head>
485
+ <meta charset="UTF-8">
486
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
487
+ <style>
488
+ body { font-family: sans-serif; padding: 20px; margin: 0; }
489
+ </style>
490
+ </head>
491
+ <body>
492
+ <one-payment id="payment"></one-payment>
493
+
494
+ <script src="https://cdn.jsdelivr.net/npm/@one-payments/web-components@1.1.28/dist/one-payment.browser.iife.js"></script>
495
+
496
+ <script>
497
+ (function() {
498
+ var el = document.getElementById('payment');
499
+
500
+ // Parse URL parameters (passed from Velo code)
501
+ var params = new URLSearchParams(window.location.search);
502
+
503
+ // Get amount from URL param, default to 0
504
+ el.amount = parseInt(params.get('amount')) || 0;
505
+ el.currency = params.get('currency') || 'USD';
506
+
507
+ // ✅ Always generate a fresh UUID for orderId
508
+ el.orderId = crypto.randomUUID();
509
+
510
+ el.config = {
511
+ apiKey: params.get('apiKey') || 'pk_demo_...',
512
+ secretKey: params.get('secretKey') || 'sk_demo_...',
513
+ environment: params.get('env') || 'demo'
514
+ };
515
+
516
+ el.adapters = OnePayments.createWebAdapters();
517
+
518
+ el.firstName = params.get('firstName') || '';
519
+ el.lastName = params.get('lastName') || '';
520
+ el.email = params.get('email') || '';
521
+
522
+ el.addEventListener('payment-success', function(event) {
523
+ window.parent.postMessage({
524
+ type: 'ONE_PAYMENT_SUCCESS',
525
+ data: event.detail
526
+ }, '*');
527
+ });
528
+
529
+ el.addEventListener('payment-error', function(event) {
530
+ window.parent.postMessage({
531
+ type: 'ONE_PAYMENT_ERROR',
532
+ data: event.detail
533
+ }, '*');
534
+ });
535
+ })();
536
+ </script>
537
+ </body>
538
+ </html>
539
+ ```
540
+
541
+ #### Velo Page Code
542
+
543
+ ```javascript
544
+ // In your Wix page code (Velo)
545
+ import wixLocation from 'wix-location';
546
+
547
+ $w.onReady(function () {
548
+ // Listen for messages from the payment iframe
549
+ $w('#html1').onMessage((event) => {
550
+ const { type, data } = event.data;
551
+
552
+ if (type === 'ONE_PAYMENT_SUCCESS') {
553
+ console.log('Payment successful:', data.paymentIntentId);
554
+ // Redirect to thank you page
555
+ wixLocation.to('/thank-you');
556
+ }
557
+
558
+ if (type === 'ONE_PAYMENT_ERROR') {
559
+ console.error('Payment failed:', data.error);
560
+ // Show error message
561
+ $w('#errorText').text = 'Payment failed. Please try again.';
562
+ $w('#errorText').show();
563
+ }
564
+ });
565
+
566
+ // Optional: Pass dynamic data to the iframe
567
+ // $w('#html1').src = `https://your-hosted-html.com/payment.html?amount=${cartTotal}&currency=USD`;
568
+ });
569
+ ```
570
+
571
+ ### Wix-Specific Notes
572
+
573
+ | Topic | Details |
574
+ |-------|---------|
575
+ | **HTML Embed size** | Set height to ~600px to fit the payment form |
576
+ | **Communication** | Use `postMessage` to communicate between iframe and Wix page |
577
+ | **Dynamic data** | Pass amount/currency via URL params or postMessage |
578
+ | **Order ID** | Always use `crypto.randomUUID()` inside the embed |
579
+ | **Styling** | The embed runs in an iframe, so Wix styles won't affect it |
580
+
581
+ ---
582
+
583
+ ## WordPress Integration
584
+
585
+ This section explains how to integrate the ONE Payments Drop-in Element into a WordPress site.
586
+
587
+ ### Integration Methods
588
+
589
+ 1. **Custom HTML Block** - For Gutenberg editor (WordPress 5.0+)
590
+ 2. **Shortcode** - For Classic editor or widgets
591
+ 3. **Theme template** - For theme developers
592
+
593
+ ### Method 1: Custom HTML Block (Gutenberg)
594
+
595
+ This is the simplest method for most WordPress users.
596
+
597
+ #### Step 1: Add a Custom HTML Block
598
+
599
+ 1. Edit your page/post in WordPress
600
+ 2. Click the **+** button to add a block
601
+ 3. Search for **"Custom HTML"**
602
+ 4. Add the Custom HTML block
603
+
604
+ #### Step 2: Paste This Code
605
+
606
+ ```html
607
+ <div id="one-payments-container" style="max-width: 500px; margin: 20px auto;">
608
+ <one-payment id="one-payment-element"></one-payment>
609
+ </div>
610
+
611
+ <!-- Load ONE Payments CDN Bundle -->
612
+ <script src="https://cdn.jsdelivr.net/npm/@one-payments/web-components@1.1.28/dist/one-payment.browser.iife.js"></script>
613
+
614
+ <script>
615
+ (function() {
616
+ // Wait for DOM ready
617
+ function initPayment() {
618
+ var el = document.getElementById('one-payment-element');
619
+
620
+ if (!el) {
621
+ console.error('[ONE Payments] Payment element not found');
622
+ return;
623
+ }
624
+
625
+ // =====================================================
626
+ // AMOUNT & CURRENCY
627
+ // =====================================================
628
+
629
+ // Set your amount in minor units (cents)
630
+ // Example: $75.00 = 7500
631
+ el.amount = 7500;
632
+
633
+ // Set your currency
634
+ el.currency = 'USD';
635
+
636
+ // =====================================================
637
+ // ORDER ID - MUST BE A UUID
638
+ // =====================================================
639
+
640
+ // ✅ CORRECT: Generate a fresh UUID
641
+ el.orderId = crypto.randomUUID();
642
+
643
+ // ❌ WRONG: Do NOT use WordPress post ID or other identifiers
644
+ // el.orderId = '12345'; // This will FAIL!
645
+
646
+ // =====================================================
647
+ // CONFIGURATION
648
+ // =====================================================
649
+
650
+ el.config = {
651
+ apiKey: 'pk_live_YOUR_API_KEY_HERE',
652
+ secretKey: 'sk_live_YOUR_SECRET_KEY_HERE',
653
+ environment: 'prod' // Use 'demo' for testing
654
+ };
655
+
656
+ el.adapters = OnePayments.createWebAdapters();
657
+
658
+ // =====================================================
659
+ // CUSTOMER INFORMATION
660
+ // =====================================================
661
+
662
+ el.firstName = 'John';
663
+ el.lastName = 'Doe';
664
+ el.email = 'john@example.com';
665
+
666
+ // =====================================================
667
+ // EVENT HANDLERS
668
+ // =====================================================
669
+
670
+ el.addEventListener('payment-success', function(event) {
671
+ console.log('Payment successful!', event.detail.paymentIntentId);
672
+
673
+ // Option 1: Redirect to thank you page
674
+ // window.location.href = '/thank-you/';
675
+
676
+ // Option 2: Show success message
677
+ document.getElementById('one-payments-container').innerHTML =
678
+ '<div style="text-align: center; padding: 40px;">' +
679
+ '<h2 style="color: green;">Payment Successful!</h2>' +
680
+ '<p>Your payment ID: ' + event.detail.paymentIntentId + '</p>' +
681
+ '</div>';
682
+ });
683
+
684
+ el.addEventListener('payment-error', function(event) {
685
+ console.error('Payment failed:', event.detail.error);
686
+ alert('Payment failed: ' + event.detail.error);
687
+ });
688
+
689
+ console.log('[ONE Payments] Initialized');
690
+ console.log('Amount:', el.amount, 'cents');
691
+ console.log('Currency:', el.currency);
692
+ console.log('Order ID:', el.orderId);
693
+ }
694
+
695
+ // Initialize when DOM is ready
696
+ if (document.readyState === 'loading') {
697
+ document.addEventListener('DOMContentLoaded', initPayment);
698
+ } else {
699
+ initPayment();
700
+ }
701
+ })();
702
+ </script>
703
+ ```
704
+
705
+ ### Method 2: WordPress Shortcode (Advanced)
706
+
707
+ For more control, create a shortcode in your theme's `functions.php`:
708
+
709
+ ```php
710
+ <?php
711
+ // Add to your theme's functions.php
712
+
713
+ function one_payments_shortcode($atts) {
714
+ // Parse shortcode attributes
715
+ $atts = shortcode_atts(array(
716
+ 'amount' => '0',
717
+ 'currency' => 'USD',
718
+ ), $atts);
719
+
720
+ // Generate unique element ID
721
+ $element_id = 'one-payment-' . uniqid();
722
+
723
+ ob_start();
724
+ ?>
725
+ <div id="<?php echo esc_attr($element_id); ?>-container" style="max-width: 500px; margin: 20px auto;">
726
+ <one-payment id="<?php echo esc_attr($element_id); ?>"></one-payment>
727
+ </div>
728
+
729
+ <script src="https://cdn.jsdelivr.net/npm/@one-payments/web-components@1.1.28/dist/one-payment.browser.iife.js"></script>
730
+
731
+ <script>
732
+ (function() {
733
+ function init() {
734
+ var el = document.getElementById('<?php echo esc_js($element_id); ?>');
735
+ if (!el) return;
736
+
737
+ el.amount = <?php echo intval($atts['amount']); ?>;
738
+ el.currency = '<?php echo esc_js($atts['currency']); ?>';
739
+
740
+ // ✅ Generate UUID for orderId
741
+ el.orderId = crypto.randomUUID();
742
+
743
+ el.config = {
744
+ apiKey: 'pk_live_YOUR_API_KEY_HERE',
745
+ secretKey: 'sk_live_YOUR_SECRET_KEY_HERE',
746
+ environment: 'prod'
747
+ };
748
+
749
+ el.adapters = OnePayments.createWebAdapters();
750
+
751
+ el.addEventListener('payment-success', function(event) {
752
+ console.log('Payment successful!', event.detail.paymentIntentId);
753
+ });
754
+
755
+ el.addEventListener('payment-error', function(event) {
756
+ console.error('Payment failed:', event.detail.error);
757
+ });
758
+ }
759
+
760
+ if (document.readyState === 'loading') {
761
+ document.addEventListener('DOMContentLoaded', init);
762
+ } else {
763
+ init();
764
+ }
765
+ })();
766
+ </script>
767
+ <?php
768
+ return ob_get_clean();
769
+ }
770
+ add_shortcode('one_payments', 'one_payments_shortcode');
771
+ ```
772
+
773
+ #### Using the Shortcode
774
+
775
+ ```
776
+ [one_payments amount="7500" currency="USD"]
777
+ ```
778
+
779
+ ### Method 3: WooCommerce Integration (Advanced)
780
+
781
+ For WooCommerce stores, you can integrate with the checkout:
782
+
783
+ ```php
784
+ <?php
785
+ // Add to your theme's functions.php or a custom plugin
786
+
787
+ add_action('woocommerce_review_order_after_payment', 'add_one_payments_to_checkout');
788
+
789
+ function add_one_payments_to_checkout() {
790
+ ?>
791
+ <div id="one-payments-wc-container" style="margin: 20px 0;">
792
+ <h3>Pay with ONE Payments</h3>
793
+ <one-payment id="one-payment-wc"></one-payment>
794
+ </div>
795
+
796
+ <script src="https://cdn.jsdelivr.net/npm/@one-payments/web-components@1.1.28/dist/one-payment.browser.iife.js"></script>
797
+
798
+ <script>
799
+ jQuery(function($) {
800
+ var el = document.getElementById('one-payment-wc');
801
+ if (!el) return;
802
+
803
+ // Get cart total (WooCommerce stores in cents)
804
+ el.amount = <?php echo intval(WC()->cart->get_total('edit') * 100); ?>;
805
+ el.currency = '<?php echo get_woocommerce_currency(); ?>';
806
+
807
+ // ✅ Generate UUID for orderId
808
+ el.orderId = crypto.randomUUID();
809
+
810
+ el.config = {
811
+ apiKey: 'pk_live_YOUR_API_KEY_HERE',
812
+ secretKey: 'sk_live_YOUR_SECRET_KEY_HERE',
813
+ environment: 'prod'
814
+ };
815
+
816
+ el.adapters = OnePayments.createWebAdapters();
817
+
818
+ // Get customer data from checkout form
819
+ el.firstName = $('#billing_first_name').val() || '';
820
+ el.lastName = $('#billing_last_name').val() || '';
821
+ el.email = $('#billing_email').val() || '';
822
+
823
+ el.addEventListener('payment-success', function(event) {
824
+ console.log('Payment successful!', event.detail.paymentIntentId);
825
+ // Proceed with WooCommerce order completion
826
+ });
827
+ });
828
+ </script>
829
+ <?php
830
+ }
831
+ ```
832
+
833
+ ### WordPress-Specific Notes
834
+
835
+ | Topic | Details |
836
+ |-------|---------|
837
+ | **Gutenberg** | Use Custom HTML block for simple integration |
838
+ | **Classic Editor** | Use shortcode method |
839
+ | **WooCommerce** | Can integrate with checkout, but orderId must still be UUID |
840
+ | **Order ID** | Always use `crypto.randomUUID()`. Never use WordPress post IDs. |
841
+ | **Amount format** | Convert to minor units (cents). $75.00 = 7500 |
842
+
843
+ ---
844
+
845
+ ## Troubleshooting
846
+
847
+ ### Common Errors
848
+
849
+ #### "Invalid orderId format"
850
+
851
+ **Cause:** The `orderId` is not a valid UUID.
852
+
853
+ **Solution:** Use `crypto.randomUUID()` to generate a proper UUID:
854
+
855
+ ```javascript
856
+ el.orderId = crypto.randomUUID();
857
+ ```
858
+
859
+ **Do NOT use:**
860
+ - Shopify `cart.token`
861
+ - WordPress post IDs
862
+ - Order numbers like `#1001`
863
+ - Any string that isn't a UUID
864
+
865
+ #### "Payment element not found"
866
+
867
+ **Cause:** JavaScript runs before the element is in the DOM.
868
+
869
+ **Solution:** Wrap your code in a DOM ready check:
870
+
871
+ ```javascript
872
+ if (document.readyState === 'loading') {
873
+ document.addEventListener('DOMContentLoaded', initPayment);
874
+ } else {
875
+ initPayment();
876
+ }
877
+ ```
878
+
879
+ #### "OnePayments is not defined"
880
+
881
+ **Cause:** The CDN script hasn't loaded yet.
882
+
883
+ **Solution:** Make sure the `<script src="...">` tag comes BEFORE your configuration script:
884
+
885
+ ```html
886
+ <!-- 1. Load the bundle FIRST -->
887
+ <script src="https://cdn.jsdelivr.net/npm/@one-payments/web-components@1.1.28/dist/one-payment.browser.iife.js"></script>
888
+
889
+ <!-- 2. THEN configure -->
890
+ <script>
891
+ // Your configuration code
892
+ </script>
893
+ ```
894
+
895
+ #### Element not rendering
896
+
897
+ **Possible causes:**
898
+ 1. Missing required properties (`amount`, `currency`, `orderId`, `config`, `adapters`)
899
+ 2. Invalid `config` object
900
+ 3. CSS hiding the element
901
+
902
+ **Solution:** Check browser console for errors and verify all required properties are set.
903
+
904
+ ---
905
+
906
+ ## Security Considerations
907
+
908
+ ### API Keys in Client-Side Code
909
+
910
+ The current integration pattern includes `secretKey` in client-side code. This is acceptable for the current use case but be aware:
911
+
912
+ - Keep your production keys secure
913
+ - Use `environment: 'demo'` for testing
914
+ - Consider using a backend proxy for additional security in the future
915
+
916
+ ### Content Security Policy (CSP)
917
+
918
+ If your site uses CSP, ensure these are allowed:
919
+
920
+ - Scripts from `cdn.jsdelivr.net` (or `unpkg.com`)
921
+ - Inline scripts (or use nonce/hash)
922
+
923
+ ---
924
+
925
+ ## API Reference
926
+
927
+ ### Global Object: `window.OnePayments`
928
+
929
+ | Property/Method | Description |
930
+ |-----------------|-------------|
931
+ | `createWebAdapters()` | Creates adapters for browser environment. Required. |
932
+ | `VERSION` | Current package version (e.g., "1.1.28") |
933
+ | `TAG_NAME` | Custom element tag name ("one-payment") |
934
+ | `isRegistered()` | Returns `true` if element is registered |
935
+ | `whenDefined()` | Promise that resolves when element is ready |
936
+
937
+ ### Element Properties
938
+
939
+ | Property | Type | Required | Description |
940
+ |----------|------|----------|-------------|
941
+ | `amount` | Number | Yes | Amount in minor units (cents) |
942
+ | `currency` | String | Yes | ISO 4217 currency code |
943
+ | `orderId` | String | Yes | **Must be a UUID** |
944
+ | `config` | Object | Yes | `{ apiKey, secretKey, environment }` |
945
+ | `adapters` | Object | Yes | From `OnePayments.createWebAdapters()` |
946
+ | `firstName` | String | No | Customer first name |
947
+ | `lastName` | String | No | Customer last name |
948
+ | `email` | String | No | Customer email |
949
+
950
+ ### Element Events
951
+
952
+ | Event | Detail | Description |
953
+ |-------|--------|-------------|
954
+ | `payment-success` | `{ paymentIntentId }` | Payment completed successfully |
955
+ | `payment-error` | `{ error }` | Payment failed |
956
+ | `state-change` | `{ state }` | Internal state changed |
957
+
958
+ ---
959
+
960
+ ## Version History
961
+
962
+ | Version | Changes |
963
+ |---------|---------|
964
+ | 1.1.28 | Fixed VERSION constant replacement in browser bundle |
965
+ | 1.1.27 | Initial CDN/IIFE bundle release |
966
+
967
+ ---
968
+
969
+ ## Notes for Existing Users
970
+
971
+ This documentation describes how to use the CDN bundle for platforms without bundlers.
972
+
973
+ **This does NOT change:**
974
+ - `src/index.ts` - ESM entry point (unchanged)
975
+ - `src/one-payment.ts` - Component implementation (unchanged)
976
+ - React/Vue/Angular/React-Native wrappers (unchanged)
977
+ - `@one-payments/core` (unchanged)
978
+ - `@one-payments/adapters-*` (unchanged)
979
+
980
+ Existing ESM-based integrations (React, Vue, Angular) continue to work exactly as before.