> ## Documentation Index
> Fetch the complete documentation index at: https://docs.unibee.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Payment iframe integration (Embedded)

> Embed UniBee payments into your app using iframe with embedded UI mode

## Overview

UniBee Payment supports iframe integration for seamless payment experiences. By setting `PaymentUIMode` to `"embedded"` in API requests, you can embed payment pages directly into your application using an iframe, eliminating the need for page redirects.

### Architecture Overview

```mermaid theme={null}
graph TB
    A[Client Application] --> B[UniBee API]
    B --> C{PaymentUIMode}
    C -->|embedded| D[Return Payment URL]
    C -->|hosted| E[Redirect to Payment Page]
    
    D --> F[Create iframe with Payment URL]
    F --> G[UniBee Payment Page in iframe]
    G --> H[User Completes Payment]
    H --> I[Payment Status Message]
    I --> J[Handle Payment Result]
    
    style A fill:#e1f5fe
    style B fill:#f3e5f5
    style G fill:#e8f5e8
    style J fill:#fff3e0
```

## API Integration

### Supported Endpoints

The following API endpoints support iframe integration:

| Endpoint                                                                                         | Description                    | PaymentUIMode Support |
| ------------------------------------------------------------------------------------------------ | ------------------------------ | --------------------- |
| [`/checkout/subscription/create_submit`](/api-reference/subscription/create-subscription)        | Create subscription (checkout) | ✅                     |
| [`/merchant/subscription/create_submit`](/api-reference/subscription/create-subscription)        | Create subscription (merchant) | ✅                     |
| [`/merchant/subscription/update_submit`](/api-reference/subscription-update/update-subscription) | Update subscription (merchant) | ✅                     |
| [`/merchant/payment/new`](/api-reference/payment/new-payment)                                    | Create one-time payment        | ✅                     |

### Request Parameters

Add the `PaymentUIMode` parameter to your API requests:

```json theme={null}
{
  "paymentUIMode": "embedded",
  // ... other parameters
}
```

### Response Structure

When `PaymentUIMode` is set to `"embedded"`, the API returns:

```json theme={null}
{
  "status": 10,
  "paymentId": "pay_xxx",
  "invoiceId": "inv_xxx", 
  "link": "https://api.unibee.dev/embedded/payment_checker?paymentId=pay_xxx&env=prod",
  "action": {
    // Payment gateway specific data
  }
}
```

**Key Fields**:

* `link`: The payment page URL to embed in iframe
* `paymentId`: Unique payment identifier
* `invoiceId`: Unique invoice identifier
* `action`: Gateway-specific payment data

### API Integration Flow

```mermaid theme={null}
sequenceDiagram
    participant Client as Client App
    participant API as UniBee API
    participant Gateway as Payment Gateway
    
    Client->>API: POST /merchant/payment/new<br/>{paymentUIMode: "embedded"}
    API->>Gateway: Create Payment Intent
    Gateway-->>API: Payment Created
    API-->>Client: Response with payment URL
    
    Note over Client: Extract link from response
    Client->>Client: Create iframe with payment URL
    Client->>Gateway: Load payment page in iframe
    
    Note over Gateway: User completes payment
    Gateway->>Client: PostMessage with payment status
    Client->>Client: Handle payment result
```

## Frontend Integration

### Frontend Integration Flow

```mermaid theme={null}
graph TD
    A[User Clicks Payment Button] --> B[Call createPayment API]
    B --> C{API Response}
    C -->|Success| D[Extract payment URL]
    C -->|Error| E[Show Error Message]
    
    D --> F[Create iframe Element]
    F --> G[Set iframe src to payment URL]
    G --> H[Show Payment Modal]
    
    H --> I[User Interacts with Payment Page]
    I --> J[Payment Gateway Processes Payment]
    
    J --> K{Payment Result}
    K -->|Success| L[Receive UniBee_PaymentSuccess Message]
    K -->|Failed| M[Receive UniBee_PaymentFailed Message]
    K -->|Cancelled| N[Receive UniBee_PaymentCancelled Message]
    
    L --> O[Close Modal & Handle Success]
    M --> P[Close Modal & Show Error]
    N --> Q[Close Modal & Show Cancellation]
    
    style A fill:#e3f2fd
    style B fill:#f3e5f5
    style H fill:#e8f5e8
    style O fill:#c8e6c9
    style P fill:#ffcdd2
    style Q fill:#fff9c4
```

### 1. Basic iframe Setup

```html theme={null}
<!DOCTYPE html>
<html>
<head>
  <title>Payment Integration</title>
  <style>
    .payment-modal {
      display: none;
      position: fixed;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      background: rgba(0,0,0,0.5);
      z-index: 1000;
    }
    
    .payment-content {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      background: white;
      border-radius: 8px;
      width: 90%;
      max-width: 800px;
      height: 80%;
      max-height: 600px;
    }
    
    .payment-iframe {
      width: 100%;
      height: 100%;
      border: none;
    }
  </style>
</head>
<body>
  <button onclick="openPayment()">Open Payment</button>
  
  <div id="paymentModal" class="payment-modal">
    <div class="payment-content">
      <iframe id="paymentIframe" class="payment-iframe" src="about:blank"></iframe>
    </div>
  </div>

  <script>
    // Message listener for iframe communication
    window.addEventListener('message', function(event) {
      console.log('Received message from iframe:', event.data);
      
      // Security verification (specify exact domain in production)
      // if (event.origin !== 'https://api.unibee.dev') return;
      
      const { type, paymentId, invoiceId } = event.data;
      
      switch (type) {
        case 'UniBee_PaymentSuccess':
          handlePaymentSuccess(paymentId, invoiceId);
          break;
        case 'UniBee_PaymentFailed':
          handlePaymentFailed(paymentId, invoiceId);
          break;
        case 'UniBee_PaymentCancelled':
          handlePaymentCancelled(paymentId, invoiceId);
          break;
      }
    });
    
    function openPayment() {
      // Call your API to create payment
      createPayment()
        .then(response => {
          const paymentUrl = response.link;
          document.getElementById('paymentIframe').src = paymentUrl;
          document.getElementById('paymentModal').style.display = 'block';
        })
        .catch(error => {
          console.error('Failed to create payment:', error);
        });
    }
    
    function closePayment() {
      document.getElementById('paymentModal').style.display = 'none';
      document.getElementById('paymentIframe').src = 'about:blank';
    }
    
    function handlePaymentSuccess(paymentId, invoiceId) {
      console.log('Payment successful:', { paymentId, invoiceId });
      closePayment();
      // Add your success handling logic here
      alert('Payment completed successfully!');
    }
    
    function handlePaymentFailed(paymentId, invoiceId) {
      console.log('Payment failed:', { paymentId, invoiceId });
      closePayment();
      // Add your failure handling logic here
      alert('Payment failed. Please try again.');
    }
    
    function handlePaymentCancelled(paymentId, invoiceId) {
      console.log('Payment cancelled:', { paymentId, invoiceId });
      closePayment();
      // Add your cancellation handling logic here
      alert('Payment was cancelled.');
    }
    
    // API call example
    async function createPayment() {
      const response = await fetch('/api/merchant/payment/new', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': 'Bearer your-token'
        },
        body: JSON.stringify({
          paymentUIMode: 'embedded',
          gatewayId: 1,
          amount: 1000,
          currency: 'USD',
          // ... other required parameters
        })
      });
      
      return await response.json();
    }
  </script>
</body>
</html>
```

### 2. React Integration Example

```jsx theme={null}
import React, { useState, useEffect } from 'react';

const PaymentModal = ({ paymentUrl, onClose, onSuccess, onFailure, onCancel }) => {
  useEffect(() => {
    const handleMessage = (event) => {
      // Security verification
      // if (event.origin !== 'https://api.unibee.dev') return;
      
      const { type, paymentId, invoiceId } = event.data;
      
      switch (type) {
        case 'UniBee_PaymentSuccess':
          onSuccess?.(paymentId, invoiceId);
          break;
        case 'UniBee_PaymentFailed':
          onFailure?.(paymentId, invoiceId);
          break;
        case 'UniBee_PaymentCancelled':
          onCancel?.(paymentId, invoiceId);
          break;
      }
    };
    
    window.addEventListener('message', handleMessage);
    return () => window.removeEventListener('message', handleMessage);
  }, [onSuccess, onFailure, onCancel]);
  
  return (
    <div className="payment-modal">
      <div className="payment-content">
        <iframe 
          src={paymentUrl} 
          className="payment-iframe"
          title="Payment"
        />
      </div>
    </div>
  );
};

const PaymentPage = () => {
  const [showPayment, setShowPayment] = useState(false);
  const [paymentUrl, setPaymentUrl] = useState('');
  
  const createPayment = async () => {
    try {
      const response = await fetch('/api/merchant/payment/new', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': 'Bearer your-token'
        },
        body: JSON.stringify({
          paymentUIMode: 'embedded',
          gatewayId: 1,
          amount: 1000,
          currency: 'USD',
        })
      });
      
      const data = await response.json();
      setPaymentUrl(data.link);
      setShowPayment(true);
    } catch (error) {
      console.error('Failed to create payment:', error);
    }
  };
  
  const handleSuccess = (paymentId, invoiceId) => {
    setShowPayment(false);
    console.log('Payment successful:', { paymentId, invoiceId });
    // Handle success
  };
  
  const handleFailure = (paymentId, invoiceId) => {
    setShowPayment(false);
    console.log('Payment failed:', { paymentId, invoiceId });
    // Handle failure
  };
  
  const handleCancel = (paymentId, invoiceId) => {
    setShowPayment(false);
    console.log('Payment cancelled:', { paymentId, invoiceId });
    // Handle cancellation
  };
  
  return (
    <div>
      <button onClick={createPayment}>Create Payment</button>
      
      {showPayment && (
        <PaymentModal
          paymentUrl={paymentUrl}
          onClose={() => setShowPayment(false)}
          onSuccess={handleSuccess}
          onFailure={handleFailure}
          onCancel={handleCancel}
        />
      )}
    </div>
  );
};
```

## Message Communication Protocol

### Message Flow Diagram

```mermaid theme={null}
sequenceDiagram
    participant App as Client Application
    participant Iframe as Payment iframe
    participant Gateway as Payment Gateway
    
    Note over App: User initiates payment
    App->>Iframe: Load payment URL
    Iframe->>Gateway: Display payment form
    
    Note over Gateway: User completes payment
    Gateway->>Gateway: Process payment
    
    alt Payment Success
        Gateway->>Iframe: Payment successful
        Iframe->>App: PostMessage: UniBee_PaymentSuccess
        App->>App: Handle success (close modal, redirect, etc.)
    else Payment Failed
        Gateway->>Iframe: Payment failed
        Iframe->>App: PostMessage: UniBee_PaymentFailed
        App->>App: Handle failure (show error, retry option)
    else Payment Cancelled
        Gateway->>Iframe: Payment cancelled
        Iframe->>App: PostMessage: UniBee_PaymentCancelled
        App->>App: Handle cancellation (close modal, show message)
    end
```

### Message Format

The iframe sends messages to the parent window in the following format:

```javascript theme={null}
{
  type: 'UniBee_PaymentSuccess',    // or PaymentFailed, PaymentCancelled
  paymentId: 'pay_xxx',             // Payment ID
  invoiceId: 'inv_xxx'              // Invoice ID (optional)
}
```

### Message Types

| Type                      | Description        | Trigger                                  |
| ------------------------- | ------------------ | ---------------------------------------- |
| `UniBee_PaymentSuccess`   | Payment successful | When payment status changes to success   |
| `UniBee_PaymentFailed`    | Payment failed     | When payment status changes to failed    |
| `UniBee_PaymentCancelled` | Payment cancelled  | When payment status changes to cancelled |

## Complete Integration Flow

### Integration Steps Overview

```mermaid theme={null}
flowchart TD
    subgraph "Step 1: API Call"
        A1[Prepare Payment Data] --> A2[Set paymentUIMode: 'embedded']
        A2 --> A3[Call UniBee API]
        A3 --> A4[Receive Response with Payment URL]
    end
    
    subgraph "Step 2: Frontend Setup"
        B1[Create iframe Element] --> B2[Set iframe src to Payment URL]
        B2 --> B3[Add iframe to DOM]
        B3 --> B4[Show Payment Modal/Container]
    end
    
    subgraph "Step 3: Message Handling"
        C1[Add message Event Listener] --> C2[Verify Message Origin]
        C2 --> C3[Parse Message Content]
        C3 --> C4[Handle Payment Result]
    end
    
    subgraph "Step 4: Payment Processing"
        D1[User Completes Payment] --> D2[Gateway Processes Payment]
        D2 --> D3[Send Status Message to Parent]
        D3 --> D4[Update UI Based on Result]
    end
    
    A4 --> B1
    B4 --> C1
    C4 --> D1
    
    style A1 fill:#e3f2fd
    style B1 fill:#f3e5f5
    style C1 fill:#e8f5e8
    style D1 fill:#fff3e0
```

### 1. Create Payment

```javascript theme={null}
// Step 1: Call API to create payment
const response = await fetch('/api/merchant/payment/new', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer your-token'
  },
  body: JSON.stringify({
    paymentUIMode: 'embedded',  // Enable iframe mode
    gatewayId: 1,
    amount: 1000,
    currency: 'USD',
    // ... other parameters
  })
});

const paymentData = await response.json();
```

### 2. Embed Payment Page

```javascript theme={null}
// Step 2: Get payment URL from response
const paymentUrl = paymentData.link; // e.g., "https://api.unibee.dev/embedded/payment_checker?paymentId=pay_xxx&env=prod"

// Step 3: Create iframe and load payment page
const iframe = document.createElement('iframe');
iframe.src = paymentUrl;
iframe.style.width = '100%';
iframe.style.height = '600px';
iframe.style.border = 'none';

document.getElementById('payment-container').appendChild(iframe);
```

### 3. Listen for Messages

```javascript theme={null}
// Step 4: Listen for payment status messages
window.addEventListener('message', function(event) {
  // Security verification
  if (event.origin !== 'https://api.unibee.dev') return;
  
  const { type, paymentId, invoiceId } = event.data;
  
  switch (type) {
    case 'UniBee_PaymentSuccess':
      // Payment completed successfully
      console.log('Payment successful:', paymentId);
      // Close iframe, redirect, or update UI
      break;
      
    case 'UniBee_PaymentFailed':
      // Payment failed
      console.log('Payment failed:', paymentId);
      // Show error message, retry option, etc.
      break;
      
    case 'UniBee_PaymentCancelled':
      // Payment was cancelled by user
      console.log('Payment cancelled:', paymentId);
      // Close iframe, show cancellation message
      break;
  }
});
```

## Security Considerations

### 1. Message Origin Verification

```javascript theme={null}
window.addEventListener('message', function(event) {
  // Always verify message origin in production
  if (event.origin !== 'https://api.unibee.dev') {
    console.warn('Ignoring message from untrusted origin:', event.origin);
    return;
  }
  
  // Process message...
});
```

### 2. Message Content Validation

```javascript theme={null}
function isValidMessage(data) {
  return data && 
         typeof data.type === 'string' && 
         data.type.startsWith('UniBee_') &&
         typeof data.paymentId === 'string';
}

window.addEventListener('message', function(event) {
  if (!isValidMessage(event.data)) {
    console.warn('Invalid message format:', event.data);
    return;
  }
  
  // Process message...
});
```

## Best Practices

### 1. Responsive Design

```css theme={null}
.payment-iframe {
  width: 100%;
  height: 600px;
  border: none;
  border-radius: 8px;
}

@media (max-width: 768px) {
  .payment-iframe {
    height: 500px;
  }
}
```

### 2. Loading States

```javascript theme={null}
function showPaymentModal(paymentUrl) {
  const modal = document.getElementById('paymentModal');
  const iframe = document.getElementById('paymentIframe');
  
  // Show loading state
  modal.style.display = 'block';
  iframe.style.display = 'none';
  
  // Load payment page
  iframe.onload = () => {
    iframe.style.display = 'block';
    // Hide loading state
  };
  
  iframe.src = paymentUrl;
}
```

### 3. Timeout Handling

```javascript theme={null}
let paymentTimeout;

function openPayment() {
  // Set timeout (e.g., 30 minutes)
  paymentTimeout = setTimeout(() => {
    closePayment();
    alert('Payment timeout. Please try again.');
  }, 30 * 60 * 1000);
  
  // Open payment...
}

function closePayment() {
  if (paymentTimeout) {
    clearTimeout(paymentTimeout);
    paymentTimeout = null;
  }
  // Close modal...
}
```

## API Reference

### PaymentUIMode Values

| Value        | Description                               |
| ------------ | ----------------------------------------- |
| `"hosted"`   | Redirect to hosted payment page (default) |
| `"embedded"` | Return URL for iframe embedding           |

### Required Headers

```javascript theme={null}
{
  'Content-Type': 'application/json',
  'Authorization': 'Bearer YOUR-API-KEY'
}
```
