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

# HTML Integration

> Learn how to integrate Phoenix using vanilla HTML and JavaScript

For non-React frameworks or custom implementations, follow this HTML integration guide.

## Step 1: Obtain Access Token

<AccordionGroup>
  <Accordion title="Obtaining Access Token">
    Before integrating Phoenix, you need to obtain an access token from your backend.

    ```javascript theme={null}
    // Example function to fetch access token from your backend
    async function getAccessToken() {
      try {
        const response = await fetch('/api/token');
        const data = await response.json();
        return data.access_token;
      } catch (error) {
        console.error('Error fetching access token:', error);
        return null;
      }
    }
    ```

    See the [Obtaining Access Token](/api-reference/access-token) page for detailed instructions on setting up the backend endpoint.
  </Accordion>
</AccordionGroup>

<Note>
  This is example code for obtaining an access token. You will need to adapt the endpoint URL and request format based on your specific backend implementation. Refer to the [Obtaining Access Token](/api-reference/access-token) page for a complete example of setting up a backend service.
</Note>

## Step 2: Add the iframe to your HTML

```html theme={null}
<div id="payment-container" style="display: none;">
  <div class="payment-overlay">
    <div class="payment-modal">
      <button 
        id="cancel-payment-button"
        class="close-button"
        aria-label="Close payment window"
      >
        &times;
      </button>
      <iframe
        id="phoenix-payment-iframe"
        src="https://app-partner.phoenix.market/"
        class="teller-iframe"
        title="Phoenix Payment"
        allow="clipboard-write"
      ></iframe>
    </div>
  </div>
</div>
```

## Step 3: Add Essential CSS

Add this CSS to style the payment container and iframe:

```css theme={null}
/* Phoenix Payment Styles */
#payment-container {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 1000;
}

.payment-overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.5);
  display: flex;
  justify-content: center;
  align-items: center;
}

.payment-modal {
  position: relative;
  background-color: transparent;
  border-radius: 12px;
  padding: 0;
  box-shadow: none;
  overflow: visible;
}

.close-button {
  position: absolute;
  top: -15px;
  right: -15px;
  background-color: #333;
  color: white;
  border: none;
  border-radius: 50%;
  width: 30px;
  height: 30px;
  font-size: 18px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 10;
  padding: 0;
  line-height: 1;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}

.teller-iframe {
  width: 350px;
  height: 600px;
  border: none;
  border-radius: 8px;
  overflow: hidden;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}
```

## Step 4: Add JavaScript for Communication

You need to add JavaScript functions to handle the integration. Here's a breakdown of the required parameters and functions:

### Required Parameters

* `walletAddress`: The Ethereum wallet address where USDC will be sent
* `amount`: The amount in USD to convert to USDC
* `accessToken`: The access token from your backend
* `onClose`: Function to handle when the user closes the payment modal
* `handlePaymentMessage`: Function to process payment response messages
* `onDone`: Function to handle when the payment process is complete (new)

### Core Functions

#### Transaction Success Data

When a transaction is successful, the data object will contain:

* `amount`: The USD amount
* `token`: The token received (e.g., "USDC")
* `chain`: The blockchain (e.g., "Base")
* `walletAddress`: The receiving wallet address
* `sendAmount`: The amount of tokens sent
* `transactionHash`: The blockchain transaction hash
* `basescanLink`: Link to view the transaction on Basescan

#### Order Created Data

When an order is created, the data object will contain:

* `order_id`: Unique identifier for the order
* `data`: Object containing additional order details:
  * `created_at`: Timestamp of order creation
  * `buyer_address`: The buyer's wallet address
  * `seller_address`: The seller's wallet address
  * `send_amount`: The amount to be sent
  * `receive_amount`: The amount to be received
  * `uniqueness_amount`: The amount of cents added to the order for uniqueness
  * `receiving_chain_id`: The chain ID where the payment will be received
  * `zelle_address`: The Zelle address for payment

```javascript theme={null}
// Function to get access token from your backend
async function getAccessToken() {
  try {
    const response = await fetch('/api/token');
    const data = await response.json();
    return data.access_token;
  } catch (error) {
    console.error('Error fetching access token:', error);
    return null;
  }
}

// Function to show payment iframe with parameters
async function showPayment(walletAddress, amount, theme) {
  const iframe = document.getElementById('phoenix-payment-iframe');
  const container = document.getElementById('payment-container');
  
  // Get the access token from your backend
  const accessToken = await getAccessToken();
  
  if (!accessToken) {
    alert('Unable to obtain access token. Please try again later.');
    return;
  }
  
  // Build iframe URL with all parameters
  let url = `https://app-partner.phoenix.market/?address=${walletAddress}&amount=${amount}&access_token=${accessToken}`;
  if (theme) {
    url += `&theme=${theme}`;
  }
  
  // Set iframe src
  iframe.src = url;
  
  // Display the container that holds the iframe
  container.style.display = 'block';
  
  // Set up event listener for messages from the iframe
  window.addEventListener('message', handlePaymentMessage);
  
  // Set up cancel button functionality
  document.getElementById('cancel-payment-button').onclick = hidePayment;
}

// Function to handle messages received from the iframe
function handlePaymentMessage(event) {
  // IMPORTANT: Verify origin for security
  if (event.origin !== 'https://app-partner.phoenix.market') return;
  
  // Handle order created message
  if (event.data?.type === 'ORDER_CREATED') {
    const { order_id, ...data } = event.data.data;
    console.log('Order created:', event.data.data);
    
    // Handle the order creation event as needed
    // You should store order details in your database, especially the order_id
  }
  // Handle transaction success message
  else if (event.data?.type === 'TRANSACTION_SUCCESS') {
    const { amount, token, chain, walletAddress, sendAmount, transactionHash, basescanLink } = event.data.data;
    console.log('Transaction successful:', transactionHash);
    
    // You should store transaction details in your database
    // and update your UI to show the payment was successful
    
    // Uncomment the following line if you want to close the window after transaction success
    // hidePayment();
  }
  // Handle cancel message
  else if (event.data?.type === 'CANCEL') {
    console.log('Payment canceled by user');
    hidePayment();
  }
  // Handle open explorer URL message
  else if (event.data?.type === 'OPEN_EXPLORER_URL') {
    const url = event.data.url;
    console.log('Opening explorer URL:', url);
    
    // Open the URL in a new tab
    window.open(url, '_blank');
  }
  // Handle done message
  else if (event.data?.type === 'USER_DONE') {
    console.log('Payment process completed');
    hidePayment();
  }
  // Handle payment failure or cancellation
  else if (event.data?.type === 'PAYMENT_FAILED' || event.data?.type === 'PAYMENT_CANCELLED') {
    console.log('Payment failed or cancelled');
    
    // Uncomment the following line if you want to close the window after payment failure/cancellation
    // hidePayment();
  }
}

// Function to hide the payment iframe
function hidePayment() {
  document.getElementById('payment-container').style.display = 'none';
  // IMPORTANT: Remove event listener to prevent memory leaks
  window.removeEventListener('message', handlePaymentMessage);
}
```

### Connecting Everything

Add this script to connect your form to the payment flow:

```javascript theme={null}
// Set up the button click handler to start the payment process
document.getElementById('start-payment').addEventListener('click', function() {
  // Get values from form inputs
  const walletAddress = document.getElementById('wallet').value;
  const amount = document.getElementById('amount').value;
  const theme = document.getElementById('theme').value; // Get selected theme
  
  // Validate inputs (basic validation)
  if (!walletAddress || !amount) {
    alert('Please enter both wallet address and amount');
    return;
  }
  
  // Start payment process with collected values
  showPayment(walletAddress, amount, theme);
});
```

## Complete Implementation Example

<AccordionGroup>
  <Accordion title="View Complete Example">
    Here's a complete example showing how to implement the Phoenix payment in an HTML page:

    ```html theme={null}
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Phoenix Payment Demo</title>
      <style>
        /* Basic page styling */
        body {
          font-family: Arial, sans-serif;
          max-width: 600px;
          margin: 0 auto;
          padding: 20px;
        }
        
        .input-group {
          margin-bottom: 15px;
        }
        
        label {
          display: block;
          margin-bottom: 5px;
          font-weight: bold;
        }
        
        input {
          width: 100%;
          padding: 8px;
          border: 1px solid #ddd;
          border-radius: 4px;
        }
        
        button {
          background-color: #16A34A;
          color: white;
          border: none;
          padding: 10px 15px;
          border-radius: 4px;
          cursor: pointer;
        }
        
        button:disabled {
          background-color: #ccc;
          cursor: not-allowed;
        }
        
        /* Phoenix Payment Styles */
        #payment-container {
          position: fixed;
          top: 0;
          left: 0;
          width: 100%;
          height: 100%;
          z-index: 1000;
          display: none;
        }
        
        .payment-overlay {
          position: absolute;
          top: 0;
          left: 0;
          width: 100%;
          height: 100%;
          background-color: rgba(0, 0, 0, 0.5);
          display: flex;
          justify-content: center;
          align-items: center;
        }
        
        .payment-modal {
          position: relative;
          background-color: transparent;
          border-radius: 12px;
          padding: 0;
          box-shadow: none;
          overflow: visible;
        }
        
        .close-button {
          position: absolute;
          top: -15px;
          right: -15px;
          background-color: #333;
          color: white;
          border: none;
          border-radius: 50%;
          width: 30px;
          height: 30px;
          font-size: 18px;
          cursor: pointer;
          display: flex;
          align-items: center;
          justify-content: center;
          z-index: 10;
          padding: 0;
          line-height: 1;
          box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
        }
        
        .teller-iframe {
          width: 350px;
          height: 600px;
          border: none;
          border-radius: 8px;
          overflow: hidden;
          box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
        }
      </style>
    </head>
    <body>
      <h1>Phoenix Payment Demo</h1>
      
      <div class="input-group">
        <label for="wallet">Wallet Address:</label>
        <input id="wallet" type="text" placeholder="0x...">
      </div>
      
      <div class="input-group">
        <label for="amount">Amount (USD):</label>
        <input id="amount" type="number" placeholder="100">
      </div>

      <!-- Add this new input group -->
      <div class="input-group">
        <label for="theme">Theme:</label>
        <select id="theme">
          <option value="">Default</option>
          <option value="light">Light</option>
          <option value="dark">Dark</option>
        </select>
      </div>
      
      <button id="start-payment">Make Payment</button>
      
      <!-- Payment Container (Hidden by default) -->
      <div id="payment-container">
        <div class="payment-overlay">
          <div class="payment-modal">
            <button 
              id="cancel-payment-button" 
              class="close-button"
              aria-label="Close payment window"
            >
              &times;
            </button>
            <iframe
              id="phoenix-payment-iframe"
              src="about:blank"
              class="teller-iframe"
              title="Phoenix Payment"
              allow="clipboard-write"
            ></iframe>
          </div>
        </div>
      </div>
      
      <script>
        // Function to get access token from your backend
        async function getAccessToken() {
          try {
            const response = await fetch('/api/token');
            const data = await response.json();
            return data.access_token;
          } catch (error) {
            console.error('Error fetching access token:', error);
            return null;
          }
        }
        
        // Function to show payment iframe with parameters
        async function showPayment(walletAddress, amount, theme) {
          const iframe = document.getElementById('phoenix-payment-iframe');
          const container = document.getElementById('payment-container');
          
          // Get the access token from your backend
          const accessToken = await getAccessToken();
          
          if (!accessToken) {
            alert('Unable to obtain access token. Please try again later.');
            return;
          }
          
          // Build iframe URL with all parameters
          let url = `https://app-partner.phoenix.market/?address=${walletAddress}&amount=${amount}&access_token=${accessToken}`;
          if (theme) {
            url += `&theme=${theme}`;
          }
          
          // Set iframe src
          iframe.src = url;
          
          // Display the container that holds the iframe
          container.style.display = 'block';
          
          // Set up event listener for messages from the iframe
          window.addEventListener('message', handlePaymentMessage);
          
          // Set up cancel button functionality
          document.getElementById('cancel-payment-button').onclick = hidePayment;
        }
        
        // Function to handle messages received from the iframe
        function handlePaymentMessage(event) {
          // IMPORTANT: Verify origin for security
          if (event.origin !== 'https://app-partner.phoenix.market') return;
          
          // Handle order created message
          if (event.data?.type === 'ORDER_CREATED') {
            const { order_id, ...data } = event.data.data;
            console.log('Order created:', event.data.data);
            
            // Handle the order creation event as needed
            // You should store order details in your database, especially the order_id
          }
          // Handle transaction success message
          else if (event.data?.type === 'TRANSACTION_SUCCESS') {
            const { amount, token, chain, walletAddress, sendAmount, transactionHash, basescanLink } = event.data.data;
            console.log('Transaction successful:', transactionHash);
            
            // You should store transaction details in your database
            // and update your UI to show the payment was successful
            
            // Uncomment the following line if you want to close the window after transaction success
            // hidePayment();
          }
          // Handle cancel message
          else if (event.data?.type === 'CANCEL') {
            console.log('Payment canceled by user');
            hidePayment();
          }
          // Handle open explorer URL message
          else if (event.data?.type === 'OPEN_EXPLORER_URL') {
            const url = event.data.url;
            console.log('Opening explorer URL:', url);
            
            // Open the URL in a new tab
            window.open(url, '_blank');
          }
          // Handle done message
          else if (event.data?.type === 'USER_DONE') {
            console.log('Payment process completed');
            hidePayment();
          }
          // Handle payment failure or cancellation
          else if (event.data?.type === 'PAYMENT_FAILED' || event.data?.type === 'PAYMENT_CANCELLED') {
            console.log('Payment failed or cancelled');
            
            // Uncomment the following line if you want to close the window after payment failure/cancellation
            // hidePayment();
          }
        }
        
        // Function to hide the payment iframe
        function hidePayment() {
          document.getElementById('payment-container').style.display = 'none';
          // IMPORTANT: Remove event listener to prevent memory leaks
          window.removeEventListener('message', handlePaymentMessage);
        }
        
        // Set up the button click handler
        document.getElementById('start-payment').addEventListener('click', function() {
          // Get values from form inputs
          const walletAddress = document.getElementById('wallet').value;
          const amount = document.getElementById('amount').value;
          const theme = document.getElementById('theme').value; // Get selected theme
          
          // Validate inputs (basic validation)
          if (!walletAddress || !amount) {
            alert('Please enter both wallet address and amount');
            return;
          }
          
          // Start payment process with collected values
          showPayment(walletAddress, amount, theme);
        });
      </script>
    </body>
    </html>
    ```
  </Accordion>
</AccordionGroup>
