# CDN Integration Guide

## Overview

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**.

The `@one-payments/web-components` package provides a browser-ready IIFE bundle that can be loaded via a simple `<script>` tag:

```html
<script src="https://cdn.jsdelivr.net/npm/@one-payments/web-components@1.1.28/dist/one-payment.browser.iife.js"></script>
```

This bundle:
- Auto-registers the `<one-payment>` custom element
- Exposes a global `window.OnePayments` API
- Bundles all dependencies (no additional scripts needed)
- Works without npm, bundlers, or build steps

---

## CRITICAL: orderId Must Be a UUID

> **This is the most important requirement. Read this section carefully.**

The backend **strictly validates** the `orderId` format. If `orderId` is not a valid UUID, the payment request **will fail**.

### What is Required

`orderId` must be a **pure UUID string** with no prefixes, suffixes, or additional data.

**Correct format (UUID v4):**
```
550e8400-e29b-41d4-a716-446655440000
```

### Examples

| Example | Valid? | Reason |
|---------|--------|--------|
| `550e8400-e29b-41d4-a716-446655440000` | ✅ Yes | Pure UUID |
| `cart-550e8400-e29b-41d4-a716-446655440000` | ❌ No | Has prefix |
| `550e8400-e29b-41d4-a716-446655440000__cartToken` | ❌ No | Has suffix |
| `550e8400-e29b-41d4-a716-446655440000-12345` | ❌ No | Extra data appended |
| `order-123` | ❌ No | Not a UUID |
| `12345` | ❌ No | Not a UUID |
| `{{ cart.token }}` (Shopify) | ❌ No | Cart token is not a UUID |

### How to Generate a UUID

Use the built-in browser API:

```javascript
const orderId = crypto.randomUUID();
// Result: "550e8400-e29b-41d4-a716-446655440000"
```

`crypto.randomUUID()` is supported in all modern browsers (Chrome 92+, Firefox 95+, Safari 15.4+, Edge 92+).

### Common Mistakes to Avoid

| Mistake | Why It's Wrong |
|---------|----------------|
| Using Shopify `cart.token` as orderId | Cart token is not a UUID format |
| Concatenating UUID with cart.token | Backend expects pure UUID only |
| Using order numbers like `#1001` | Not a UUID format |
| Reusing the same orderId for multiple payments | Each payment attempt needs a fresh UUID |

---

## General Usage Pattern

This pattern works on **any platform** that supports `<script>` tags:

```html
<!-- 1. Load the CDN bundle -->
<script src="https://cdn.jsdelivr.net/npm/@one-payments/web-components@1.1.28/dist/one-payment.browser.iife.js"></script>

<!-- 2. Place the web component -->
<one-payment id="one-payment-element"></one-payment>

<!-- 3. Configure via JavaScript -->
<script>
  var el = document.getElementById('one-payment-element');

  // Amount in minor units (e.g., cents)
  // 5000 = $50.00 USD
  el.amount = 5000;

  // ISO 4217 currency code
  el.currency = 'USD';

  // ✅ CRITICAL: Generate a fresh UUID for each payment
  el.orderId = crypto.randomUUID();

  // Configuration
  el.config = {
    apiKey: 'pk_live_...',      // Your public API key
    secretKey: 'sk_live_...',   // Your secret key
    environment: 'prod'          // 'prod' or 'demo'
  };

  // Create browser adapters
  el.adapters = OnePayments.createWebAdapters();

  // Customer information
  el.firstName = 'John';
  el.lastName = 'Doe';
  el.email = 'john@example.com';

  // Handle successful payment
  el.addEventListener('payment-success', function(event) {
    console.log('Payment successful!', event.detail.paymentIntentId);
    // Redirect to success page or update UI
  });

  // Handle payment error
  el.addEventListener('payment-error', function(event) {
    console.error('Payment failed:', event.detail.error);
    // Show error message to user
  });
</script>
```

### Required Properties

| Property | Type | Description |
|----------|------|-------------|
| `amount` | Number | Amount in minor units (cents). Example: `5000` = $50.00 |
| `currency` | String | ISO 4217 currency code. Example: `'USD'`, `'SGD'`, `'EUR'` |
| `orderId` | String | **Must be a UUID.** Use `crypto.randomUUID()` |
| `config` | Object | Contains `apiKey`, `secretKey`, `environment` |
| `adapters` | Object | Use `OnePayments.createWebAdapters()` |

### Optional Properties

| Property | Type | Description |
|----------|------|-------------|
| `firstName` | String | Customer's first name |
| `lastName` | String | Customer's last name |
| `email` | String | Customer's email address |

### Events

| Event | Description |
|-------|-------------|
| `payment-success` | Fired when payment completes successfully. `event.detail.paymentIntentId` contains the payment ID. |
| `payment-error` | Fired when payment fails. `event.detail.error` contains error information. |
| `state-change` | Fired when internal state changes. `event.detail.state` contains current state. |

---

## Shopify Integration

This section explains how to integrate the ONE Payments Drop-in Element into a Shopify theme.

### Where to Add the Code

You can add this code to:
- `sections/cart-template.liquid` - For cart page integration
- `snippets/one-payments.liquid` - As a reusable snippet
- `templates/cart.liquid` - For older themes

### Understanding Shopify Data

Shopify provides these Liquid variables:
- `{{ cart.total_price }}` - Cart total in minor units (cents)
- `{{ shop.currency }}` - Store currency code (e.g., "USD")
- `{{ customer.first_name }}` - Customer's first name (if logged in)
- `{{ customer.last_name }}` - Customer's last name (if logged in)
- `{{ customer.email }}` - Customer's email (if logged in)

> **Important:** Do NOT use `{{ cart.token }}` as orderId. Cart token is not a UUID.

### Complete Shopify Example

Create a new file `snippets/one-payments-dropin.liquid`:

```liquid
{% comment %}
  ONE Payments Drop-in Element

  Usage: {% render 'one-payments-dropin' %}

  IMPORTANT: orderId must be a UUID generated via crypto.randomUUID()
  Do NOT use cart.token as orderId - it will fail backend validation.
{% endcomment %}

<div id="one-payments-container" style="max-width: 500px; margin: 20px auto;">
  <one-payment id="one-payment-element"></one-payment>
</div>

<!-- Load ONE Payments CDN Bundle -->
<script src="https://cdn.jsdelivr.net/npm/@one-payments/web-components@1.1.28/dist/one-payment.browser.iife.js"></script>

<script>
  (function() {
    // Wait for DOM to be ready
    if (document.readyState === 'loading') {
      document.addEventListener('DOMContentLoaded', initPayment);
    } else {
      initPayment();
    }

    function initPayment() {
      var el = document.getElementById('one-payment-element');

      if (!el) {
        console.error('[ONE Payments] Payment element not found');
        return;
      }

      // =====================================================
      // AMOUNT & CURRENCY (from Shopify Liquid)
      // =====================================================

      // cart.total_price is in minor units (cents)
      // Example: $50.00 = 5000
      el.amount = {{ cart.total_price }};

      // Shop currency (e.g., "USD", "SGD", "EUR")
      el.currency = "{{ shop.currency }}";

      // =====================================================
      // ORDER ID - MUST BE A UUID
      // =====================================================

      // ✅ CORRECT: Generate a fresh UUID for each payment
      el.orderId = crypto.randomUUID();

      // ❌ WRONG: Do NOT use cart.token
      // el.orderId = "{{ cart.token }}";  // This will FAIL!

      // ❌ WRONG: Do NOT concatenate with other values
      // el.orderId = crypto.randomUUID() + "__{{ cart.token }}";  // This will FAIL!

      // =====================================================
      // CONFIGURATION
      // =====================================================

      el.config = {
        apiKey: 'pk_live_YOUR_API_KEY_HERE',
        secretKey: 'sk_live_YOUR_SECRET_KEY_HERE',
        environment: 'prod'  // Use 'demo' for testing
      };

      // Create browser adapters
      el.adapters = OnePayments.createWebAdapters();

      // =====================================================
      // CUSTOMER INFORMATION (optional but recommended)
      // =====================================================

      {% if customer %}
        // Logged-in customer - use their saved information
        el.firstName = {{ customer.first_name | json }};
        el.lastName = {{ customer.last_name | json }};
        el.email = {{ customer.email | json }};
      {% else %}
        // Guest checkout - you may want to collect this via a form
        // or leave empty and let the payment form collect it
        el.firstName = '';
        el.lastName = '';
        el.email = '';
      {% endif %}

      // =====================================================
      // EVENT HANDLERS
      // =====================================================

      // Handle successful payment
      el.addEventListener('payment-success', function(event) {
        console.log('[ONE Payments] Payment successful!');
        console.log('Payment Intent ID:', event.detail.paymentIntentId);

        // Option 1: Redirect to thank you page
        // window.location.href = '/pages/thank-you';

        // Option 2: Redirect to Shopify checkout to complete order
        // window.location.href = '/checkout';

        // Option 3: Show success message
        alert('Payment successful! Order ID: ' + event.detail.paymentIntentId);
      });

      // Handle payment error
      el.addEventListener('payment-error', function(event) {
        console.error('[ONE Payments] Payment failed:', event.detail.error);
        alert('Payment failed: ' + event.detail.error);
      });

      // Optional: Handle state changes for loading indicators
      el.addEventListener('state-change', function(event) {
        var state = event.detail.state;
        console.log('[ONE Payments] State changed to:', state.status);

        // You can show/hide loading indicators here
        // if (state.status === 'processing') { showLoading(); }
        // if (state.status === 'ready') { hideLoading(); }
      });

      console.log('[ONE Payments] Payment element initialized');
      console.log('Amount:', el.amount, 'cents');
      console.log('Currency:', el.currency);
      console.log('Order ID:', el.orderId);
    }
  })();
</script>
```

### Using the Snippet

In your cart template (`sections/cart-template.liquid` or similar), add:

```liquid
{% render 'one-payments-dropin' %}
```

### Shopify-Specific Notes

| Topic | Details |
|-------|---------|
| **Amount format** | `cart.total_price` is already in minor units (cents). No conversion needed. |
| **Currency** | `shop.currency` gives the ISO code. Use it directly. |
| **Customer data** | Use `{% if customer %}` to check if user is logged in. |
| **Order ID** | Always use `crypto.randomUUID()`. Never use `cart.token`. |
| **Checkout flow** | After payment success, you may redirect to Shopify checkout or a custom thank-you page. |

### Testing on Shopify

1. Use `environment: 'demo'` for testing
2. Use demo API keys (not production keys)
3. Check browser console for any errors
4. Verify the payment element renders correctly
5. Test with a demo card number

---

## Wix Integration

This section explains how to integrate the ONE Payments Drop-in Element into a Wix site.

### Integration Methods

Wix offers two ways to add custom code:

1. **HTML Embed** - Simple, no coding required beyond the snippet
2. **Velo (Wix Code)** - More advanced, allows dynamic data

### Method 1: HTML Embed (Simple)

This is the easiest method for most Wix users.

#### Step 1: Add an HTML Embed Element

1. In Wix Editor, click **Add** (+)
2. Select **Embed** > **Custom Embeds** > **Embed a Widget**
3. Click **Enter Code**

#### Step 2: Paste This Code

```html
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
    body {
      font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
      padding: 20px;
    }
    #payment-container {
      max-width: 100%;
    }
  </style>
</head>
<body>
  <div id="payment-container">
    <one-payment id="payment"></one-payment>
  </div>

  <!-- Load ONE Payments CDN Bundle -->
  <script src="https://cdn.jsdelivr.net/npm/@one-payments/web-components@1.1.28/dist/one-payment.browser.iife.js"></script>

  <script>
    (function() {
      var el = document.getElementById('payment');

      if (!el) {
        console.error('[ONE Payments] Payment element not found');
        return;
      }

      // =====================================================
      // AMOUNT & CURRENCY
      // =====================================================

      // Set your amount in minor units (cents)
      // Example: $50.00 = 5000
      el.amount = 5000;

      // Set your currency
      el.currency = 'USD';

      // =====================================================
      // ORDER ID - MUST BE A UUID
      // =====================================================

      // ✅ CORRECT: Generate a fresh UUID
      el.orderId = crypto.randomUUID();

      // =====================================================
      // CONFIGURATION
      // =====================================================

      el.config = {
        apiKey: 'pk_live_YOUR_API_KEY_HERE',
        secretKey: 'sk_live_YOUR_SECRET_KEY_HERE',
        environment: 'prod'  // Use 'demo' for testing
      };

      el.adapters = OnePayments.createWebAdapters();

      // =====================================================
      // CUSTOMER INFORMATION
      // =====================================================

      el.firstName = 'John';
      el.lastName = 'Doe';
      el.email = 'john@example.com';

      // =====================================================
      // EVENT HANDLERS
      // =====================================================

      // Handle successful payment
      el.addEventListener('payment-success', function(event) {
        console.log('Payment successful!', event.detail.paymentIntentId);

        // Notify parent Wix page
        window.parent.postMessage({
          type: 'ONE_PAYMENT_SUCCESS',
          paymentIntentId: event.detail.paymentIntentId
        }, '*');
      });

      // Handle payment error
      el.addEventListener('payment-error', function(event) {
        console.error('Payment failed:', event.detail.error);

        // Notify parent Wix page
        window.parent.postMessage({
          type: 'ONE_PAYMENT_ERROR',
          error: event.detail.error
        }, '*');
      });

      console.log('[ONE Payments] Initialized with Order ID:', el.orderId);
    })();
  </script>
</body>
</html>
```

#### Step 3: Resize the Embed

- Set width to 100% or a fixed width like 500px
- Set height to approximately 600px (adjust as needed)

### Method 2: Velo (Advanced)

If you need to pass dynamic data (like cart amount), use Velo page code.

#### HTML Embed (with URL parameters)

```html
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <style>
    body { font-family: sans-serif; padding: 20px; margin: 0; }
  </style>
</head>
<body>
  <one-payment id="payment"></one-payment>

  <script src="https://cdn.jsdelivr.net/npm/@one-payments/web-components@1.1.28/dist/one-payment.browser.iife.js"></script>

  <script>
    (function() {
      var el = document.getElementById('payment');

      // Parse URL parameters (passed from Velo code)
      var params = new URLSearchParams(window.location.search);

      // Get amount from URL param, default to 0
      el.amount = parseInt(params.get('amount')) || 0;
      el.currency = params.get('currency') || 'USD';

      // ✅ Always generate a fresh UUID for orderId
      el.orderId = crypto.randomUUID();

      el.config = {
        apiKey: params.get('apiKey') || 'pk_demo_...',
        secretKey: params.get('secretKey') || 'sk_demo_...',
        environment: params.get('env') || 'demo'
      };

      el.adapters = OnePayments.createWebAdapters();

      el.firstName = params.get('firstName') || '';
      el.lastName = params.get('lastName') || '';
      el.email = params.get('email') || '';

      el.addEventListener('payment-success', function(event) {
        window.parent.postMessage({
          type: 'ONE_PAYMENT_SUCCESS',
          data: event.detail
        }, '*');
      });

      el.addEventListener('payment-error', function(event) {
        window.parent.postMessage({
          type: 'ONE_PAYMENT_ERROR',
          data: event.detail
        }, '*');
      });
    })();
  </script>
</body>
</html>
```

#### Velo Page Code

```javascript
// In your Wix page code (Velo)
import wixLocation from 'wix-location';

$w.onReady(function () {
  // Listen for messages from the payment iframe
  $w('#html1').onMessage((event) => {
    const { type, data } = event.data;

    if (type === 'ONE_PAYMENT_SUCCESS') {
      console.log('Payment successful:', data.paymentIntentId);
      // Redirect to thank you page
      wixLocation.to('/thank-you');
    }

    if (type === 'ONE_PAYMENT_ERROR') {
      console.error('Payment failed:', data.error);
      // Show error message
      $w('#errorText').text = 'Payment failed. Please try again.';
      $w('#errorText').show();
    }
  });

  // Optional: Pass dynamic data to the iframe
  // $w('#html1').src = `https://your-hosted-html.com/payment.html?amount=${cartTotal}&currency=USD`;
});
```

### Wix-Specific Notes

| Topic | Details |
|-------|---------|
| **HTML Embed size** | Set height to ~600px to fit the payment form |
| **Communication** | Use `postMessage` to communicate between iframe and Wix page |
| **Dynamic data** | Pass amount/currency via URL params or postMessage |
| **Order ID** | Always use `crypto.randomUUID()` inside the embed |
| **Styling** | The embed runs in an iframe, so Wix styles won't affect it |

---

## WordPress Integration

This section explains how to integrate the ONE Payments Drop-in Element into a WordPress site.

### Integration Methods

1. **Custom HTML Block** - For Gutenberg editor (WordPress 5.0+)
2. **Shortcode** - For Classic editor or widgets
3. **Theme template** - For theme developers

### Method 1: Custom HTML Block (Gutenberg)

This is the simplest method for most WordPress users.

#### Step 1: Add a Custom HTML Block

1. Edit your page/post in WordPress
2. Click the **+** button to add a block
3. Search for **"Custom HTML"**
4. Add the Custom HTML block

#### Step 2: Paste This Code

```html
<div id="one-payments-container" style="max-width: 500px; margin: 20px auto;">
  <one-payment id="one-payment-element"></one-payment>
</div>

<!-- Load ONE Payments CDN Bundle -->
<script src="https://cdn.jsdelivr.net/npm/@one-payments/web-components@1.1.28/dist/one-payment.browser.iife.js"></script>

<script>
  (function() {
    // Wait for DOM ready
    function initPayment() {
      var el = document.getElementById('one-payment-element');

      if (!el) {
        console.error('[ONE Payments] Payment element not found');
        return;
      }

      // =====================================================
      // AMOUNT & CURRENCY
      // =====================================================

      // Set your amount in minor units (cents)
      // Example: $75.00 = 7500
      el.amount = 7500;

      // Set your currency
      el.currency = 'USD';

      // =====================================================
      // ORDER ID - MUST BE A UUID
      // =====================================================

      // ✅ CORRECT: Generate a fresh UUID
      el.orderId = crypto.randomUUID();

      // ❌ WRONG: Do NOT use WordPress post ID or other identifiers
      // el.orderId = '12345';  // This will FAIL!

      // =====================================================
      // CONFIGURATION
      // =====================================================

      el.config = {
        apiKey: 'pk_live_YOUR_API_KEY_HERE',
        secretKey: 'sk_live_YOUR_SECRET_KEY_HERE',
        environment: 'prod'  // Use 'demo' for testing
      };

      el.adapters = OnePayments.createWebAdapters();

      // =====================================================
      // CUSTOMER INFORMATION
      // =====================================================

      el.firstName = 'John';
      el.lastName = 'Doe';
      el.email = 'john@example.com';

      // =====================================================
      // EVENT HANDLERS
      // =====================================================

      el.addEventListener('payment-success', function(event) {
        console.log('Payment successful!', event.detail.paymentIntentId);

        // Option 1: Redirect to thank you page
        // window.location.href = '/thank-you/';

        // Option 2: Show success message
        document.getElementById('one-payments-container').innerHTML =
          '<div style="text-align: center; padding: 40px;">' +
          '<h2 style="color: green;">Payment Successful!</h2>' +
          '<p>Your payment ID: ' + event.detail.paymentIntentId + '</p>' +
          '</div>';
      });

      el.addEventListener('payment-error', function(event) {
        console.error('Payment failed:', event.detail.error);
        alert('Payment failed: ' + event.detail.error);
      });

      console.log('[ONE Payments] Initialized');
      console.log('Amount:', el.amount, 'cents');
      console.log('Currency:', el.currency);
      console.log('Order ID:', el.orderId);
    }

    // Initialize when DOM is ready
    if (document.readyState === 'loading') {
      document.addEventListener('DOMContentLoaded', initPayment);
    } else {
      initPayment();
    }
  })();
</script>
```

### Method 2: WordPress Shortcode (Advanced)

For more control, create a shortcode in your theme's `functions.php`:

```php
<?php
// Add to your theme's functions.php

function one_payments_shortcode($atts) {
    // Parse shortcode attributes
    $atts = shortcode_atts(array(
        'amount' => '0',
        'currency' => 'USD',
    ), $atts);

    // Generate unique element ID
    $element_id = 'one-payment-' . uniqid();

    ob_start();
    ?>
    <div id="<?php echo esc_attr($element_id); ?>-container" style="max-width: 500px; margin: 20px auto;">
        <one-payment id="<?php echo esc_attr($element_id); ?>"></one-payment>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/@one-payments/web-components@1.1.28/dist/one-payment.browser.iife.js"></script>

    <script>
    (function() {
        function init() {
            var el = document.getElementById('<?php echo esc_js($element_id); ?>');
            if (!el) return;

            el.amount = <?php echo intval($atts['amount']); ?>;
            el.currency = '<?php echo esc_js($atts['currency']); ?>';

            // ✅ Generate UUID for orderId
            el.orderId = crypto.randomUUID();

            el.config = {
                apiKey: 'pk_live_YOUR_API_KEY_HERE',
                secretKey: 'sk_live_YOUR_SECRET_KEY_HERE',
                environment: 'prod'
            };

            el.adapters = OnePayments.createWebAdapters();

            el.addEventListener('payment-success', function(event) {
                console.log('Payment successful!', event.detail.paymentIntentId);
            });

            el.addEventListener('payment-error', function(event) {
                console.error('Payment failed:', event.detail.error);
            });
        }

        if (document.readyState === 'loading') {
            document.addEventListener('DOMContentLoaded', init);
        } else {
            init();
        }
    })();
    </script>
    <?php
    return ob_get_clean();
}
add_shortcode('one_payments', 'one_payments_shortcode');
```

#### Using the Shortcode

```
[one_payments amount="7500" currency="USD"]
```

### Method 3: WooCommerce Integration (Advanced)

For WooCommerce stores, you can integrate with the checkout:

```php
<?php
// Add to your theme's functions.php or a custom plugin

add_action('woocommerce_review_order_after_payment', 'add_one_payments_to_checkout');

function add_one_payments_to_checkout() {
    ?>
    <div id="one-payments-wc-container" style="margin: 20px 0;">
        <h3>Pay with ONE Payments</h3>
        <one-payment id="one-payment-wc"></one-payment>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/@one-payments/web-components@1.1.28/dist/one-payment.browser.iife.js"></script>

    <script>
    jQuery(function($) {
        var el = document.getElementById('one-payment-wc');
        if (!el) return;

        // Get cart total (WooCommerce stores in cents)
        el.amount = <?php echo intval(WC()->cart->get_total('edit') * 100); ?>;
        el.currency = '<?php echo get_woocommerce_currency(); ?>';

        // ✅ Generate UUID for orderId
        el.orderId = crypto.randomUUID();

        el.config = {
            apiKey: 'pk_live_YOUR_API_KEY_HERE',
            secretKey: 'sk_live_YOUR_SECRET_KEY_HERE',
            environment: 'prod'
        };

        el.adapters = OnePayments.createWebAdapters();

        // Get customer data from checkout form
        el.firstName = $('#billing_first_name').val() || '';
        el.lastName = $('#billing_last_name').val() || '';
        el.email = $('#billing_email').val() || '';

        el.addEventListener('payment-success', function(event) {
            console.log('Payment successful!', event.detail.paymentIntentId);
            // Proceed with WooCommerce order completion
        });
    });
    </script>
    <?php
}
```

### WordPress-Specific Notes

| Topic | Details |
|-------|---------|
| **Gutenberg** | Use Custom HTML block for simple integration |
| **Classic Editor** | Use shortcode method |
| **WooCommerce** | Can integrate with checkout, but orderId must still be UUID |
| **Order ID** | Always use `crypto.randomUUID()`. Never use WordPress post IDs. |
| **Amount format** | Convert to minor units (cents). $75.00 = 7500 |

---

## Troubleshooting

### Common Errors

#### "Invalid orderId format"

**Cause:** The `orderId` is not a valid UUID.

**Solution:** Use `crypto.randomUUID()` to generate a proper UUID:

```javascript
el.orderId = crypto.randomUUID();
```

**Do NOT use:**
- Shopify `cart.token`
- WordPress post IDs
- Order numbers like `#1001`
- Any string that isn't a UUID

#### "Payment element not found"

**Cause:** JavaScript runs before the element is in the DOM.

**Solution:** Wrap your code in a DOM ready check:

```javascript
if (document.readyState === 'loading') {
  document.addEventListener('DOMContentLoaded', initPayment);
} else {
  initPayment();
}
```

#### "OnePayments is not defined"

**Cause:** The CDN script hasn't loaded yet.

**Solution:** Make sure the `<script src="...">` tag comes BEFORE your configuration script:

```html
<!-- 1. Load the bundle FIRST -->
<script src="https://cdn.jsdelivr.net/npm/@one-payments/web-components@1.1.28/dist/one-payment.browser.iife.js"></script>

<!-- 2. THEN configure -->
<script>
  // Your configuration code
</script>
```

#### Element not rendering

**Possible causes:**
1. Missing required properties (`amount`, `currency`, `orderId`, `config`, `adapters`)
2. Invalid `config` object
3. CSS hiding the element

**Solution:** Check browser console for errors and verify all required properties are set.

---

## Security Considerations

### API Keys in Client-Side Code

The current integration pattern includes `secretKey` in client-side code. This is acceptable for the current use case but be aware:

- Keep your production keys secure
- Use `environment: 'demo'` for testing
- Consider using a backend proxy for additional security in the future

### Content Security Policy (CSP)

If your site uses CSP, ensure these are allowed:

- Scripts from `cdn.jsdelivr.net` (or `unpkg.com`)
- Inline scripts (or use nonce/hash)

---

## API Reference

### Global Object: `window.OnePayments`

| Property/Method | Description |
|-----------------|-------------|
| `createWebAdapters()` | Creates adapters for browser environment. Required. |
| `VERSION` | Current package version (e.g., "1.1.28") |
| `TAG_NAME` | Custom element tag name ("one-payment") |
| `isRegistered()` | Returns `true` if element is registered |
| `whenDefined()` | Promise that resolves when element is ready |

### Element Properties

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `amount` | Number | Yes | Amount in minor units (cents) |
| `currency` | String | Yes | ISO 4217 currency code |
| `orderId` | String | Yes | **Must be a UUID** |
| `config` | Object | Yes | `{ apiKey, secretKey, environment }` |
| `adapters` | Object | Yes | From `OnePayments.createWebAdapters()` |
| `firstName` | String | No | Customer first name |
| `lastName` | String | No | Customer last name |
| `email` | String | No | Customer email |

### Element Events

| Event | Detail | Description |
|-------|--------|-------------|
| `payment-success` | `{ paymentIntentId }` | Payment completed successfully |
| `payment-error` | `{ error }` | Payment failed |
| `state-change` | `{ state }` | Internal state changed |

---

## Version History

| Version | Changes |
|---------|---------|
| 1.1.28 | Fixed VERSION constant replacement in browser bundle |
| 1.1.27 | Initial CDN/IIFE bundle release |

---

## Notes for Existing Users

This documentation describes how to use the CDN bundle for platforms without bundlers.

**This does NOT change:**
- `src/index.ts` - ESM entry point (unchanged)
- `src/one-payment.ts` - Component implementation (unchanged)
- React/Vue/Angular/React-Native wrappers (unchanged)
- `@one-payments/core` (unchanged)
- `@one-payments/adapters-*` (unchanged)

Existing ESM-based integrations (React, Vue, Angular) continue to work exactly as before.
