***

title: EmbeddedMethod UI
subtitle: Learn how to use the EmbeddedMethod UI embedded component to add the ability to securely store a payment profile or execute a sale
description: Integrate EmbeddedMethod UI to securely store payment profiles or execute sales. Configure card, ACH, and check inputs with full styling and behavior control
og:description: Integrate EmbeddedMethod UI to securely store payment profiles or execute sales. Configure card, ACH, and check inputs with full styling and behavior control
keywords: embedded payments, EmbeddedMethod UI, embedded components, payment form, card payments, ACH payments, checkout integration
icon: puzzle-piece
slug: guides/pay-in-components-embeddedmethod-ui
---------------------

This is Payabli documentation. For a complete page index, fetch https://docs.payabli.com/llms.txt — append .md to any page URL for lightweight markdown. For section-level indexes, query parameters, and other AI-optimized access methods, see https://docs.payabli.com/ai-agents.md

<AudienceInfo audiences={['developers']} />

Use the EmbeddedMethod component to capture a payment method or make a sale using any payment method. This is the most flexible and customizable component Payabli offers to developers.

<Tip>
  This component is supported in the Playground. Use the [Embedded Component Playground](https://playground.payabli.com) to edit and design embedded components in real time, and export the code to use in your own site or app.
</Tip>

## Usage

This section shows how to use the EmbeddedMethod UI component in your project.
Use the interactive demo to see how the component works, then follow the configuration walkthrough to set it up in your project.

<Info>
  See [Library URLs](/guides/pay-in-components-overview#library-urls) for important information about embedded components library URLs.
</Info>

### Interactive demo

This demo shows the component in action with transaction processing and visual feedback.
When the component processes a transaction, the demo displays the JSON response.

<EmbeddedIframe src="https://files.buildwithfern.com/payabli.docs.buildwithfern.com/a4b6043341462b6768348068eb2085e4053f1ef033909b6b5b38a5dfc815613c/snippets/demos/embedded-method.html" title="EmbeddedMethod UI Demo" height="500px" camera={true} />

### Configuration walkthrough

<div class="sr-only">
  /// Include the Payabli Script

  First, add the Payabli embedded component script to your HTML.
  Make sure to include the `data-test` attribute for testing in the sandbox environment.
  Including `<meta charset="UTF-8">` in the `<head>` element prevents problems with special characters such as 'á' or 'ñ'.

  ```html
  <!DOCTYPE html>
  <html>
  <head>
    <meta charset="UTF-8">
    <title>Payabli Integration</title>
  </head>
  <body>
    <script src="https://embedded-component-sandbox.payabli.com/component.js" data-test></script>
  </body>
  </html>
  ```

  /// Create the Container and Tab Structure

  Add a container element where the embedded component will render.
  The `id` attribute becomes the `rootContainer` in your configuration.
  Create tabs to switch between card, ACH, and RDC payment methods.

  ```html focus=8-19
  <!DOCTYPE html>
  <html>
  <head>
    <meta charset="UTF-8">
    <title>Payabli Integration</title>
  </head>
  <body>
    <h1>Payment Form</h1>
    <div class="payment-container">
      <div class="tabs">
        <button class="tab active" data-method="card">Payment Card</button>
        <button class="tab" data-method="ach">Bank Debit</button>
        <button class="tab" data-method="rdc">Check Capture</button>
      </div>
      <div class="form-content">
        <div id="pay-component-1"></div>
        <button id="submit-btn" class="hidden">Process Payment</button>
      </div>
    </div>
    
    <script src="https://embedded-component-sandbox.payabli.com/component.js" data-test></script>
  </body>
  </html>
  ```

  /// Add Basic Styling

  Add CSS styles for the tabs to handle active and focus states.

  ```html focus=6-53
  <!DOCTYPE html>
  <html>
  <head>
    <meta charset="UTF-8">
    <title>Payabli Integration</title>
    <style>
      .tabs {
        display: flex;
        border-bottom: 1px solid #e5e5e5;
        margin-bottom: 20px;
      }
      
      .tab {
        flex: 1;
        padding: 16px 24px;
        text-align: center;
        cursor: pointer;
        background: white;
        border: none;
        border-bottom: 2px solid transparent;
        transition: all 0.2s ease;
      }
      
      .tab:hover {
        color: #333;
        background: #f8f9fa;
      }
      
      .tab.active {
        color: #007bff;
        border-bottom-color: #007bff;
      }
      
      .hidden { 
        display: none; 
      }
      
      #submit-btn {
        background: #4f46e5;
        color: white;
        padding: 12px 24px;
        border: none;
        border-radius: 6px;
        cursor: pointer;
        margin-top: 16px;
      }
      
      #submit-btn:disabled {
        background: #9ca3af;
        cursor: not-allowed;
      }
    </style>
  </head>
  <body>
    <h1>Payment Form</h1>
    <div class="payment-container">
      <div class="tabs">
        <button class="tab active" data-method="card">Payment Card</button>
        <button class="tab" data-method="ach">Bank Debit</button>
        <button class="tab" data-method="rdc">Check Capture</button>
      </div>
      <div class="form-content">
        <div id="pay-component-1"></div>
        <button id="submit-btn" class="hidden">Process Payment</button>
      </div>
    </div>
    
    <script src="https://embedded-component-sandbox.payabli.com/component.js" data-test></script>
  </body>
  </html>
  ```

  /// Configure Card Payment Method

  Create the configuration object for card payments.
  The `token` must be a **public API token**.

  ```html focus=70-159
  <!DOCTYPE html>
  <html>
  <head>
    <meta charset="UTF-8">
    <title>Payabli Integration</title>
    <style>
      .tabs {
        display: flex;
        border-bottom: 1px solid #e5e5e5;
        margin-bottom: 20px;
      }
      
      .tab {
        flex: 1;
        padding: 16px 24px;
        text-align: center;
        cursor: pointer;
        background: white;
        border: none;
        border-bottom: 2px solid transparent;
        transition: all 0.2s ease;
      }
      
      .tab:hover {
        color: #333;
        background: #f8f9fa;
      }
      
      .tab.active {
        color: #007bff;
        border-bottom-color: #007bff;
      }
      
      .hidden { 
        display: none; 
      }
      
      #submit-btn {
        background: #4f46e5;
        color: white;
        padding: 12px 24px;
        border: none;
        border-radius: 6px;
        cursor: pointer;
        margin-top: 16px;
      }
      
      #submit-btn:disabled {
        background: #9ca3af;
        cursor: not-allowed;
      }
    </style>
  </head>
  <body>
    <h1>Payment Form</h1>
    <div class="payment-container">
      <div class="tabs">
        <button class="tab active" data-method="card">Payment Card</button>
        <button class="tab" data-method="ach">Bank Debit</button>
        <button class="tab" data-method="rdc">Check Capture</button>
      </div>
      <div class="form-content">
        <div id="pay-component-1"></div>
        <button id="submit-btn" class="hidden">Process Payment</button>
      </div>
    </div>
    
    <script src="https://embedded-component-sandbox.payabli.com/component.js" data-test></script>
    <script>
      let payComponent;
      
      const cardConfig = {
        type: "methodEmbedded",
        rootContainer: "pay-component-1",
        token: "your-public-api-token",
        entryPoint: "your-entry-point",
        defaultOpen: "card",
        temporaryToken: false,
        card: {
          enabled: true,
          amex: true,
          discover: true,
          visa: true,
          mastercard: true,
          jcb: true,
          diners: true,
          inputs: {
            cardHolderName: { 
              label: "NAME ON CARD", 
              size: 12, 
              row: 0, 
              order: 0 
            },
            cardNumber: { 
              label: "CARD NUMBER", 
              size: 6, 
              row: 1, 
              order: 0 
            },
            cardExpirationDate: { 
              label: "EXPIRATION", 
              size: 6, 
              row: 1, 
              order: 1 
            },
            cardCvv: {
              label: "CVV",
              size: 6,
              row: 2,
              order: 0
            },
            cardZipcode: {
              label: "ZIP CODE",
              size: 6,
              row: 2,
              order: 1
            }
          }
        },
        functionCallBackSuccess: function (response) {
          // This callback covers both 2XX and 4XX responses
          console.log(response);
          switch (response.responseText) {
            case "Success":
              // Tokenization was successful
              alert(`Success: ${response.responseData.resultText}`);
              break;
            case "Declined":
              // Tokenization failed due to processor decline or validation errors
              // Recommend reinitialization of the component so that the user can try again
              // with different card data
              alert(`Declined: ${response.responseData.resultText}`);
              payComponent.payabliExec("reinit");
              break;
            default:
              // Other response text. These are normally errors with Payabli internal validations
              // before processor engagement
              // We recommend reinitializing the component.
              // If the problem persists, contact Payabli to help debug
              alert(`Error: ${response.responseText}`);
              payComponent.payabliExec("reinit");
              break;
          }
        },
        functionCallBackError: function(errors) {
          console.log("Payment error:", errors);
          alert("Payment processing error occurred");
          payComponent.payabliExec("reinit");
        },
        functionCallBackReady: function(data) {
          const btn = document.getElementById("submit-btn");
          if (data[1] === true) {
            btn.classList.remove("hidden");
          } else {
            btn.classList.add("hidden");
          }
        }
      };
    </script>
  </body>
  </html>
  ```

  /// Configure ACH Payment Method

  Create the configuration object for ACH payments.
  The `token` must be a **public API token**.

  ```html focus=160-243
  <!DOCTYPE html>
  <html>
  <head>
    <meta charset="UTF-8">
    <title>Payabli Integration</title>
    <style>
      .tabs {
        display: flex;
        border-bottom: 1px solid #e5e5e5;
        margin-bottom: 20px;
      }
      
      .tab {
        flex: 1;
        padding: 16px 24px;
        text-align: center;
        cursor: pointer;
        background: white;
        border: none;
        border-bottom: 2px solid transparent;
        transition: all 0.2s ease;
      }
      
      .tab:hover {
        color: #333;
        background: #f8f9fa;
      }
      
      .tab.active {
        color: #007bff;
        border-bottom-color: #007bff;
      }
      
      .hidden { 
        display: none; 
      }
      
      #submit-btn {
        background: #4f46e5;
        color: white;
        padding: 12px 24px;
        border: none;
        border-radius: 6px;
        cursor: pointer;
        margin-top: 16px;
      }
      
      #submit-btn:disabled {
        background: #9ca3af;
        cursor: not-allowed;
      }
    </style>
  </head>
  <body>
    <h1>Payment Form</h1>
    <div class="payment-container">
      <div class="tabs">
        <button class="tab active" data-method="card">Payment Card</button>
        <button class="tab" data-method="ach">Bank Debit</button>
        <button class="tab" data-method="rdc">Check Capture</button>
      </div>
      <div class="form-content">
        <div id="pay-component-1"></div>
        <button id="submit-btn" class="hidden">Process Payment</button>
      </div>
    </div>
    
    <script src="https://embedded-component-sandbox.payabli.com/component.js" data-test></script>
    <script>
      let payComponent;
      
      const cardConfig = {
        type: "methodEmbedded",
        rootContainer: "pay-component-1",
        token: "your-public-api-token",
        entryPoint: "your-entry-point",
        defaultOpen: "card",
        temporaryToken: false,
        card: {
          enabled: true,
          amex: true,
          discover: true,
          visa: true,
          mastercard: true,
          jcb: true,
          diners: true,
          inputs: {
            cardHolderName: { 
              label: "NAME ON CARD", 
              size: 12, 
              row: 0, 
              order: 0 
            },
            cardNumber: { 
              label: "CARD NUMBER", 
              size: 6, 
              row: 1, 
              order: 0 
            },
            cardExpirationDate: { 
              label: "EXPIRATION", 
              size: 6, 
              row: 1, 
              order: 1 
            },
            cardCvv: {
              label: "CVV",
              size: 6,
              row: 2,
              order: 0
            },
            cardZipcode: {
              label: "ZIP CODE",
              size: 6,
              row: 2,
              order: 1
            }
          }
        },
        functionCallBackSuccess: function (response) {
          // This callback covers both 2XX and 4XX responses
          console.log(response);
          switch (response.responseText) {
            case "Success":
              // Tokenization was successful
              alert(`Success: ${response.responseData.resultText}`);
              break;
            case "Declined":
              // Tokenization failed due to processor decline or validation errors
              // Recommend reinitialization of the component so that the user can try again
              // with different card data
              alert(`Declined: ${response.responseData.resultText}`);
              payComponent.payabliExec("reinit");
              break;
            default:
              // Other response text. These are normally errors with Payabli internal validations
              // before processor engagement
              // We recommend reinitializing the component.
              // If the problem persists, contact Payabli to help debug
              alert(`Error: ${response.responseText}`);
              payComponent.payabliExec("reinit");
              break;
          }
        },
        functionCallBackError: function(errors) {
          console.log("Payment error:", errors);
          alert("Payment processing error occurred");
          payComponent.payabliExec("reinit");
        },
        functionCallBackReady: function(data) {
          const btn = document.getElementById("submit-btn");
          if (data[1] === true) {
            btn.classList.remove("hidden");
          } else {
            btn.classList.add("hidden");
          }
        }
      };
      
      const achConfig = {
        type: "methodEmbedded",
        rootContainer: "pay-component-1",
        token: "your-public-api-token",
        entryPoint: "your-entry-point",
        defaultOpen: "ach",
        temporaryToken: false,
        ach: {
          enabled: true,
          checking: true,
          savings: true,
          inputs: {
            achAccountHolderName: {
              label: "ACCOUNT HOLDER NAME",
              placeholder: "Account Holder Name",
              floating: false,
              size: 6,
              row: 0,
              order: 0
            },
            achRouting: {
              label: "ROUTING NUMBER",
              placeholder: "123456789",
              floating: false,
              size: 6,
              row: 1,
              order: 0
            },
            achAccount: {
              label: "ACCOUNT NUMBER",
              placeholder: "Account Number",
              floating: false,
              size: 6,
              row: 1,
              order: 1
            },
            achAccountType: {
              label: "ACCOUNT TYPE",
              floating: false,
              size: 6,
              row: 0,
              order: 1
            }
          }
        },
        functionCallBackSuccess: function (response) {
          // This callback covers both 2XX and 4XX responses
          console.log(response);
          switch (response.responseText) {
            case "Success":
              // Tokenization was successful
              alert(`Success: ${response.responseData.resultText}`);
              break;
            case "Declined":
              // Tokenization failed due to processor decline or validation errors
              // Recommend reinitialization of the component so that the user can try again
              // with different card data
              alert(`Declined: ${response.responseData.resultText}`);
              payComponent.payabliExec("reinit");
              break;
            default:
              // Other response text. These are normally errors with Payabli internal validations
              // before processor engagement
              // We recommend reinitializing the component.
              // If the problem persists, contact Payabli to help debug
              alert(`Error: ${response.responseText}`);
              payComponent.payabliExec("reinit");
              break;
          }
        },
        functionCallBackError: function(errors) {
          console.log("Payment error:", errors);
          alert("Payment processing error occurred");
          payComponent.payabliExec("reinit");
        },
        functionCallBackReady: function(data) {
          const btn = document.getElementById("submit-btn");
          if (data[1] === true) {
            btn.classList.remove("hidden");
          } else {
            btn.classList.add("hidden");
          }
        }
      };
    </script>
  </body>
  </html>
  ```

  /// Configure RDC Payment Method

  Create the configuration object for RDC (Remote Deposit Capture) payments.
  The `token` must be a **public API token**.

  ```html focus=227-278
  <!DOCTYPE html>
  <html>
  <head>
    <meta charset="UTF-8">
    <title>Payabli Integration</title>
    <style>
      .tabs {
        display: flex;
        border-bottom: 1px solid #e5e5e5;
        margin-bottom: 20px;
      }
      
      .tab {
        flex: 1;
        padding: 16px 24px;
        text-align: center;
        cursor: pointer;
        background: white;
        border: none;
        border-bottom: 2px solid transparent;
        transition: all 0.2s ease;
      }
      
      .tab:hover {
        color: #333;
        background: #f8f9fa;
      }
      
      .tab.active {
        color: #007bff;
        border-bottom-color: #007bff;
      }
      
      .hidden { 
        display: none; 
      }
      
      #submit-btn {
        background: #4f46e5;
        color: white;
        padding: 12px 24px;
        border: none;
        border-radius: 6px;
        cursor: pointer;
        margin-top: 16px;
      }
      
      #submit-btn:disabled {
        background: #9ca3af;
        cursor: not-allowed;
      }
    </style>
  </head>
  <body>
    <h1>Payment Form</h1>
    <div class="payment-container">
      <div class="tabs">
        <button class="tab active" data-method="card">Payment Card</button>
        <button class="tab" data-method="ach">Bank Debit</button>
        <button class="tab" data-method="rdc">Check Capture</button>
      </div>
      <div class="form-content">
        <div id="pay-component-1"></div>
        <button id="submit-btn" class="hidden">Process Payment</button>
      </div>
    </div>
    
    <script src="https://embedded-component-sandbox.payabli.com/component.js" data-test></script>
    <script>
      let payComponent;
      
      const cardConfig = {
        type: "methodEmbedded",
        rootContainer: "pay-component-1",
        token: "your-public-api-token",
        entryPoint: "your-entry-point",
        defaultOpen: "card",
        temporaryToken: false,
        card: {
          enabled: true,
          amex: true,
          discover: true,
          visa: true,
          mastercard: true,
          jcb: true,
          diners: true,
          inputs: {
            cardHolderName: { 
              label: "NAME ON CARD", 
              size: 12, 
              row: 0, 
              order: 0 
            },
            cardNumber: { 
              label: "CARD NUMBER", 
              size: 6, 
              row: 1, 
              order: 0 
            },
            cardExpirationDate: { 
              label: "EXPIRATION", 
              size: 6, 
              row: 1, 
              order: 1 
            },
            cardCvv: {
              label: "CVV",
              size: 6,
              row: 2,
              order: 0
            },
            cardZipcode: {
              label: "ZIP CODE",
              size: 6,
              row: 2,
              order: 1
            }
          }
        },
        functionCallBackSuccess: function (response) {
          console.log(response);
          switch (response.responseText) {
            case "Success":
              alert(`Success: ${response.responseData.resultText}`);
              break;
            case "Declined":
              alert(`Declined: ${response.responseData.resultText}`);
              payComponent.payabliExec("reinit");
              break;
            default:
              alert(`Error: ${response.responseText}`);
              payComponent.payabliExec("reinit");
              break;
          }
        },
        functionCallBackError: function(errors) {
          console.log("Payment error:", errors);
          alert("Payment processing error occurred");
          payComponent.payabliExec("reinit");
        },
        functionCallBackReady: function(data) {
          const btn = document.getElementById("submit-btn");
          if (data[1] === true) {
            btn.classList.remove("hidden");
          } else {
            btn.classList.add("hidden");
          }
        }
      };
      
      const achConfig = {
        type: "methodEmbedded",
        rootContainer: "pay-component-1",
        token: "your-public-api-token",
        entryPoint: "your-entry-point",
        defaultOpen: "ach",
        temporaryToken: false,
        ach: {
          enabled: true,
          checking: true,
          savings: true,
          inputs: {
            achAccountHolderName: {
              label: "ACCOUNT HOLDER NAME",
              placeholder: "Account Holder Name",
              floating: false,
              size: 6,
              row: 0,
              order: 0
            },
            achRouting: {
              label: "ROUTING NUMBER",
              placeholder: "123456789",
              floating: false,
              size: 6,
              row: 1,
              order: 0
            },
            achAccount: {
              label: "ACCOUNT NUMBER",
              placeholder: "Account Number",
              floating: false,
              size: 6,
              row: 1,
              order: 1
            },
            achAccountType: {
              label: "ACCOUNT TYPE",
              floating: false,
              size: 6,
              row: 0,
              order: 1
            }
          }
        },
        functionCallBackSuccess: function (response) {
          console.log(response);
          switch (response.responseText) {
            case "Success":
              alert(`Success: ${response.responseData.resultText}`);
              break;
            case "Declined":
              alert(`Declined: ${response.responseData.resultText}`);
              payComponent.payabliExec("reinit");
              break;
            default:
              alert(`Error: ${response.responseText}`);
              payComponent.payabliExec("reinit");
              break;
          }
        },
        functionCallBackError: function(errors) {
          console.log("Payment error:", errors);
          alert("Payment processing error occurred");
          payComponent.payabliExec("reinit");
        },
        functionCallBackReady: function(data) {
          const btn = document.getElementById("submit-btn");
          if (data[1] === true) {
            btn.classList.remove("hidden");
          } else {
            btn.classList.add("hidden");
          }
        }
      };
      
      const rdcConfig = {
        type: "methodEmbedded",
        rootContainer: "pay-component-1",
        token: "your-public-api-token",
        entryPoint: "your-entry-point",
        defaultOpen: "rdc",
        temporaryToken: false,
        card: { enabled: true },
        rdc: {
          enabled: true,
          amount: 100,
          inputs: {
            rdcAccountHolderName: {
              label: "ACCOUNT HOLDER NAME",
              placeholder: "Account Holder Name",
              floating: false,
              size: 6,
              row: 0,
              order: 0
            },
            rdcAmount: {
              label: "AMOUNT",
              placeholder: "Amount",
              floating: false,
              size: 6,
              row: 0,
              order: 0,
            }
          }
        },
        functionCallBackSuccess: function (response) {
          console.log(response);
          switch (response.responseText) {
            case "Success":
              alert(`Success: ${response.responseData.resultText}`);
              break;
            case "Declined":
              alert(`Declined: ${response.responseData.resultText}`);
              payComponent.payabliExec("reinit");
              break;
            default:
              alert(`Error: ${response.responseText}`);
              payComponent.payabliExec("reinit");
              break;
          }
        },
        functionCallBackError: function(errors) {
          console.log("Payment error:", errors);
          alert("Payment processing error occurred");
          payComponent.payabliExec("reinit");
        },
        functionCallBackReady: function(data) {
          const btn = document.getElementById("submit-btn");
          if (data[1] === true) {
            btn.classList.remove("hidden");
          } else {
            btn.classList.add("hidden");
          }
        }
      };
    </script>
  </body>
  </html>
  ```

  /// Add Tab Switching Logic

  Add JavaScript code for the tabs. The code handles reinitializing the component when users change payment methods.

  ```html focus=280-298
  <!DOCTYPE html>
  <html>
  <head>
    <meta charset="UTF-8">
    <title>Payabli Integration</title>
    <style>
      .tabs {
        display: flex;
        border-bottom: 1px solid #e5e5e5;
        margin-bottom: 20px;
      }
      
      .tab {
        flex: 1;
        padding: 16px 24px;
        text-align: center;
        cursor: pointer;
        background: white;
        border: none;
        border-bottom: 2px solid transparent;
        transition: all 0.2s ease;
      }
      
      .tab:hover {
        color: #333;
        background: #f8f9fa;
      }
      
      .tab.active {
        color: #007bff;
        border-bottom-color: #007bff;
      }
      
      .hidden { 
        display: none; 
      }
      
      #submit-btn {
        background: #4f46e5;
        color: white;
        padding: 12px 24px;
        border: none;
        border-radius: 6px;
        cursor: pointer;
        margin-top: 16px;
      }
      
      #submit-btn:disabled {
        background: #9ca3af;
        cursor: not-allowed;
      }
    </style>
  </head>
  <body>
    <h1>Payment Form</h1>
    <div class="payment-container">
      <div class="tabs">
        <button class="tab active" data-method="card">Payment Card</button>
        <button class="tab" data-method="ach">Bank Debit</button>
        <button class="tab" data-method="rdc">Check Capture</button>
      </div>
      <div class="form-content">
        <div id="pay-component-1"></div>
        <button id="submit-btn" class="hidden">Process Payment</button>
      </div>
    </div>
    
    <script src="https://embedded-component-sandbox.payabli.com/component.js" data-test></script>
    <script>
      let payComponent;
      
      const cardConfig = {
        type: "methodEmbedded",
        rootContainer: "pay-component-1",
        token: "your-public-api-token",
        entryPoint: "your-entry-point",
        defaultOpen: "card",
        temporaryToken: false,
        card: {
          enabled: true,
          amex: true,
          discover: true,
          visa: true,
          mastercard: true,
          jcb: true,
          diners: true,
          inputs: {
            cardHolderName: { 
              label: "NAME ON CARD", 
              size: 12, 
              row: 0, 
              order: 0 
            },
            cardNumber: { 
              label: "CARD NUMBER", 
              size: 6, 
              row: 1, 
              order: 0 
            },
            cardExpirationDate: { 
              label: "EXPIRATION", 
              size: 6, 
              row: 1, 
              order: 1 
            },
            cardCvv: {
              label: "CVV",
              size: 6,
              row: 2,
              order: 0
            },
            cardZipcode: {
              label: "ZIP CODE",
              size: 6,
              row: 2,
              order: 1
            }
          }
        },
        functionCallBackSuccess: function (response) {
          console.log(response);
          switch (response.responseText) {
            case "Success":
              alert(`Success: ${response.responseData.resultText}`);
              break;
            case "Declined":
              alert(`Declined: ${response.responseData.resultText}`);
              payComponent.payabliExec("reinit");
              break;
            default:
              alert(`Error: ${response.responseText}`);
              payComponent.payabliExec("reinit");
              break;
          }
        },
        functionCallBackError: function(errors) {
          console.log("Payment error:", errors);
          alert("Payment processing error occurred");
          payComponent.payabliExec("reinit");
        },
        functionCallBackReady: function(data) {
          const btn = document.getElementById("submit-btn");
          if (data[1] === true) {
            btn.classList.remove("hidden");
          } else {
            btn.classList.add("hidden");
          }
        }
      };
      
      const achConfig = {
        type: "methodEmbedded",
        rootContainer: "pay-component-1",
        token: "your-public-api-token",
        entryPoint: "your-entry-point",
        defaultOpen: "ach",
        temporaryToken: false,
        ach: {
          enabled: true,
          checking: true,
          savings: true,
          inputs: {
            achAccountHolderName: {
              label: "ACCOUNT HOLDER NAME",
              placeholder: "Account Holder Name",
              floating: false,
              size: 6,
              row: 0,
              order: 0
            },
            achRouting: {
              label: "ROUTING NUMBER",
              placeholder: "123456789",
              floating: false,
              size: 6,
              row: 1,
              order: 0
            },
            achAccount: {
              label: "ACCOUNT NUMBER",
              placeholder: "Account Number",
              floating: false,
              size: 6,
              row: 1,
              order: 1
            },
            achAccountType: {
              label: "ACCOUNT TYPE",
              floating: false,
              size: 6,
              row: 0,
              order: 1
            }
          }
        },
        functionCallBackSuccess: function (response) {
          console.log(response);
          switch (response.responseText) {
            case "Success":
              alert(`Success: ${response.responseData.resultText}`);
              break;
            case "Declined":
              alert(`Declined: ${response.responseData.resultText}`);
              payComponent.payabliExec("reinit");
              break;
            default:
              alert(`Error: ${response.responseText}`);
              payComponent.payabliExec("reinit");
              break;
          }
        },
        functionCallBackError: function(errors) {
          console.log("Payment error:", errors);
          alert("Payment processing error occurred");
          payComponent.payabliExec("reinit");
        },
        functionCallBackReady: function(data) {
          const btn = document.getElementById("submit-btn");
          if (data[1] === true) {
            btn.classList.remove("hidden");
          } else {
            btn.classList.add("hidden");
          }
        }
      };
      
      const rdcConfig = {
        type: "methodEmbedded",
        rootContainer: "pay-component-1",
        token: "your-public-api-token",
        entryPoint: "your-entry-point",
        defaultOpen: "rdc",
        temporaryToken: false,
        card: { enabled: true },
        rdc: {
          enabled: true,
          amount: 100,
          inputs: {
            rdcAccountHolderName: {
              label: "ACCOUNT HOLDER NAME",
              placeholder: "Account Holder Name",
              floating: false,
              size: 6,
              row: 0,
              order: 0
            },
            rdcAmount: {
              label: "AMOUNT",
              placeholder: "Amount",
              floating: false,
              size: 6,
              row: 0,
              order: 0,
            }
          }
        },
        functionCallBackSuccess: function (response) {
          console.log(response);
          switch (response.responseText) {
            case "Success":
              alert(`Success: ${response.responseData.resultText}`);
              break;
            case "Declined":
              alert(`Declined: ${response.responseData.resultText}`);
              payComponent.payabliExec("reinit");
              break;
            default:
              alert(`Error: ${response.responseText}`);
              payComponent.payabliExec("reinit");
              break;
          }
        },
        functionCallBackError: function(errors) {
          console.log("Payment error:", errors);
          alert("Payment processing error occurred");
          payComponent.payabliExec("reinit");
        },
        functionCallBackReady: function(data) {
          const btn = document.getElementById("submit-btn");
          if (data[1] === true) {
            btn.classList.remove("hidden");
          } else {
            btn.classList.add("hidden");
          }
        }
      };
      
      // Tab switching
      document.querySelectorAll('.tab').forEach(tab => {
        tab.addEventListener('click', function() {
          const method = this.dataset.method;
          
          // Update active tab
          document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
          this.classList.add('active');
          
          // Create new component with appropriate config
          if (method === 'card') {
            payComponent = new PayabliComponent(cardConfig);
          } else if (method === 'ach') {
            payComponent = new PayabliComponent(achConfig);
          } else if (method === 'rdc') {
            payComponent = new PayabliComponent(rdcConfig);
          }
        });
      });
    </script>
  </body>
  </html>
  ```

  /// Initialize and Execute Payment

  Use the `payabliExec('pay')` function to perform payment processing logic.
  This function processes a secure one-time payment with the embedded component.

  ```html focus=301-322
  <!DOCTYPE html>
  <html>
  <head>
    <meta charset="UTF-8">
    <title>Payabli Integration</title>
    <style>
      .tabs {
        display: flex;
        border-bottom: 1px solid #e5e5e5;
        margin-bottom: 20px;
      }
      
      .tab {
        flex: 1;
        padding: 16px 24px;
        text-align: center;
        cursor: pointer;
        background: white;
        border: none;
        border-bottom: 2px solid transparent;
        transition: all 0.2s ease;
      }
      
      .tab:hover {
        color: #333;
        background: #f8f9fa;
      }
      
      .tab.active {
        color: #007bff;
        border-bottom-color: #007bff;
      }
      
      .hidden { 
        display: none; 
      }
      
      #submit-btn {
        background: #4f46e5;
        color: white;
        padding: 12px 24px;
        border: none;
        border-radius: 6px;
        cursor: pointer;
        margin-top: 16px;
      }
      
      #submit-btn:disabled {
        background: #9ca3af;
        cursor: not-allowed;
      }
    </style>
  </head>
  <body>
    <h1>Payment Form</h1>  
    <p>Enter your payment information below:</p>
    <div class="payment-container">
      <div class="tabs">
        <button class="tab active" data-method="card">Payment Card</button>
        <button class="tab" data-method="ach">Bank Debit</button>
        <button class="tab" data-method="rdc">Check Capture</button>
      </div>
      <div class="form-content">
        <div id="pay-component-1"></div>
        <button id="submit-btn" class="hidden">Process Payment</button>
      </div>
    </div>
    
    <script src="https://embedded-component-sandbox.payabli.com/component.js" data-test></script>
    <script>
      let payComponent;
      
      const cardConfig = {
        type: "methodEmbedded",
        rootContainer: "pay-component-1",
        token: "your-public-api-token",
        entryPoint: "your-entry-point",
        defaultOpen: "card",
        temporaryToken: false,
        card: {
          enabled: true,
          amex: true,
          discover: true,
          visa: true,
          mastercard: true,
          jcb: true,
          diners: true,
          inputs: {
            cardHolderName: { 
              label: "NAME ON CARD", 
              size: 12, 
              row: 0, 
              order: 0 
            },
            cardNumber: { 
              label: "CARD NUMBER", 
              size: 6, 
              row: 1, 
              order: 0 
            },
            cardExpirationDate: { 
              label: "EXPIRATION", 
              size: 6, 
              row: 1, 
              order: 1 
            },
            cardCvv: {
              label: "CVV",
              size: 6,
              row: 2,
              order: 0
            },
            cardZipcode: {
              label: "ZIP CODE",
              size: 6,
              row: 2,
              order: 1
            }
          }
        },
        functionCallBackSuccess: function (response) {
          console.log(response);
          switch (response.responseText) {
            case "Success":
              alert(`Success: ${response.responseData.resultText}`);
              break;
            case "Declined":
              alert(`Declined: ${response.responseData.resultText}`);
              payComponent.payabliExec("reinit");
              break;
            default:
              alert(`Error: ${response.responseText}`);
              payComponent.payabliExec("reinit");
              break;
          }
        },
        functionCallBackError: function(errors) {
          console.log("Payment error:", errors);
          alert("Payment processing error occurred");
          payComponent.payabliExec("reinit");
        },
        functionCallBackReady: function(data) {
          const btn = document.getElementById("submit-btn");
          if (data[1] === true) {
            btn.classList.remove("hidden");
          } else {
            btn.classList.add("hidden");
          }
        }
      };
      
      const achConfig = {
        type: "methodEmbedded",
        rootContainer: "pay-component-1",
        token: "your-public-api-token",
        entryPoint: "your-entry-point",
        defaultOpen: "ach",
        temporaryToken: false,
        ach: {
          enabled: true,
          checking: true,
          savings: true,
          inputs: {
            achAccountHolderName: {
              label: "ACCOUNT HOLDER NAME",
              placeholder: "Account Holder Name",
              floating: false,
              size: 6,
              row: 0,
              order: 0
            },
            achRouting: {
              label: "ROUTING NUMBER",
              placeholder: "123456789",
              floating: false,
              size: 6,
              row: 1,
              order: 0
            },
            achAccount: {
              label: "ACCOUNT NUMBER",
              placeholder: "Account Number",
              floating: false,
              size: 6,
              row: 1,
              order: 1
            },
            achAccountType: {
              label: "ACCOUNT TYPE",
              floating: false,
              size: 6,
              row: 0,
              order: 1
            }
          }
        },
        functionCallBackSuccess: function (response) {
          console.log(response);
          switch (response.responseText) {
            case "Success":
              alert(`Success: ${response.responseData.resultText}`);
              break;
            case "Declined":
              alert(`Declined: ${response.responseData.resultText}`);
              payComponent.payabliExec("reinit");
              break;
            default:
              alert(`Error: ${response.responseText}`);
              payComponent.payabliExec("reinit");
              break;
          }
        },
        functionCallBackError: function(errors) {
          console.log("Payment error:", errors);
          alert("Payment processing error occurred");
          payComponent.payabliExec("reinit");
        },
        functionCallBackReady: function(data) {
          const btn = document.getElementById("submit-btn");
          if (data[1] === true) {
            btn.classList.remove("hidden");
          } else {
            btn.classList.add("hidden");
          }
        }
      };
      
      const rdcConfig = {
        type: "methodEmbedded",
        rootContainer: "pay-component-1",
        token: "your-public-api-token",
        entryPoint: "your-entry-point",
        defaultOpen: "rdc",
        temporaryToken: false,
        card: { enabled: true },
        rdc: {
          enabled: true,
          amount: 100,
          inputs: {
            rdcAccountHolderName: {
              label: "ACCOUNT HOLDER NAME",
              placeholder: "Account Holder Name",
              floating: false,
              size: 6,
              row: 0,
              order: 0
            },
            rdcAmount: {
              label: "AMOUNT",
              placeholder: "Amount",
              floating: false,
              size: 6,
              row: 0,
              order: 0,
            }
          }
        },
        functionCallBackSuccess: function (response) {
          console.log(response);
          switch (response.responseText) {
            case "Success":
              alert(`Success: ${response.responseData.resultText}`);
              break;
            case "Declined":
              alert(`Declined: ${response.responseData.resultText}`);
              payComponent.payabliExec("reinit");
              break;
            default:
              alert(`Error: ${response.responseText}`);
              payComponent.payabliExec("reinit");
              break;
          }
        },
        functionCallBackError: function(errors) {
          console.log("Payment error:", errors);
          alert("Payment processing error occurred");
          payComponent.payabliExec("reinit");
        },
        functionCallBackReady: function(data) {
          const btn = document.getElementById("submit-btn");
          if (data[1] === true) {
            btn.classList.remove("hidden");
          } else {
            btn.classList.add("hidden");
          }
        }
      };
      
      // Tab switching
      document.querySelectorAll('.tab').forEach(tab => {
        tab.addEventListener('click', function() {
          const method = this.dataset.method;
          
          // Update active tab
          document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
          this.classList.add('active');
          
          // Create new component with appropriate config
          if (method === 'card') {
            payComponent = new PayabliComponent(cardConfig);
          } else if (method === 'ach') {
            payComponent = new PayabliComponent(achConfig);
          } else if (method === 'rdc') {
            payComponent = new PayabliComponent(rdcConfig);
          }
        });
      });
      
      // Initialize the Payabli component
      payComponent = new PayabliComponent(cardConfig);
      
      // Handle payment execution
      document.getElementById("submit-btn").addEventListener("click", function() {
        payComponent.payabliExec('pay', {
          paymentDetails: {
            totalAmount: 100.00,
            serviceFee: 0,
            categories: [{
              label: "payment",
              amount: 100.00,
              qty: 1
            }]
          },
          customerData: {
            firstName: "John",
            lastName: "Doe",
            billingEmail: "john.doe@example.com"
          }
        });
      });
    </script>
  </body>
  </html>
  ```
</div>

<div class="sr-only">
  /// Include the Payabli Script

  First, add the Payabli embedded component script to your HTML.
  Make sure to include the `data-test` attribute for testing in the sandbox environment.
  This loads the core `PayabliComponent` class that powers all embedded components.
  Including `<meta charset="UTF-8">` in the `<head>` element prevents problems with special characters such as 'á' or 'ñ'.

  ```html
  <!DOCTYPE html>
  <html>
  <head>
    <meta charset="UTF-8">
    <title>Payabli Integration - Temporary Token Flow</title>
  </head>
  <body>
    <script src="https://embedded-component-sandbox.payabli.com/component.js" data-test></script>
  </body>
  </html>
  ```

  /// Create the Container and Tab Structure

  Add a container element where the embedded component will render.
  The `id` attribute becomes the `rootContainer` in your configuration.
  Create tabs to switch between card and ACH payment methods.

  ```html focus=8-18
  <!DOCTYPE html>
  <html>
  <head>
    <meta charset="UTF-8">
    <title>Payabli Integration</title>
  </head>
  <body>
    <h1>Payment Form</h1>
    <div class="payment-container">
      <div class="tabs">
        <button class="tab active" data-method="card">Payment Card</button>
        <button class="tab" data-method="ach">Bank Debit</button>
      </div>
      <div class="form-content">
        <div id="pay-component-1"></div>
        <button id="submit-btn" class="hidden">Get Token</button>
      </div>
    </div>
    
    <script src="https://embedded-component-sandbox.payabli.com/component.js" data-test></script>
  </body>
  </html>
  ```

  /// Add Basic Styling

  Add CSS styles for the tabs to handle active and focus states.

  ```html focus=6-52
  <!DOCTYPE html>
  <html>
  <head>
    <meta charset="UTF-8">
    <title>Payabli Integration</title>
    <style>
      .tabs {
        display: flex;
        border-bottom: 1px solid #e5e5e5;
        margin-bottom: 20px;
      }
      
      .tab {
        flex: 1;
        padding: 16px 24px;
        text-align: center;
        cursor: pointer;
        background: white;
        border: none;
        border-bottom: 2px solid transparent;
        transition: all 0.2s ease;
      }
      
      .tab:hover {
        color: #333;
        background: #f8f9fa;
      }
      
      .tab.active {
        color: #007bff;
        border-bottom-color: #007bff;
      }
      
      .hidden { 
        display: none; 
      }
      
      #submit-btn {
        background: #4f46e5;
        color: white;
        padding: 12px 24px;
        border: none;
        border-radius: 6px;
        cursor: pointer;
        margin-top: 16px;
      }
      
      #submit-btn:disabled {
        background: #9ca3af;
        cursor: not-allowed;
      }
    </style>
  </head>
  <body>
    <h1>Payment Form</h1>
    <div class="payment-container">
      <div class="tabs">
        <button class="tab active" data-method="card">Payment Card</button>
        <button class="tab" data-method="ach">Bank Debit</button>
      </div>
      <div class="form-content">
        <div id="pay-component-1"></div>
        <button id="submit-btn" class="hidden">Process Payment</button>
      </div>
    </div>
    
    <script src="https://embedded-component-sandbox.payabli.com/component.js" data-test></script>
  </body>
  </html>
  ```

  /// Configure Card Payment Method

  Create the configuration object for card payments with `temporaryToken: true`.
  This setting enables the temporary token flow. See [Temp token flow](/guides/platform-developer-tokenization-temp-flow) for more information about the temporary token flow.
  The `token` must be a **public API token**.

  ```html focus=68-157
  <!DOCTYPE html>
  <html>
  <head>
    <meta charset="UTF-8">
    <title>Payabli Integration</title>
    <style>
      .tabs {
        display: flex;
        border-bottom: 1px solid #e5e5e5;
        margin-bottom: 20px;
      }
      
      .tab {
        flex: 1;
        padding: 16px 24px;
        text-align: center;
        cursor: pointer;
        background: white;
        border: none;
        border-bottom: 2px solid transparent;
        transition: all 0.2s ease;
      }
      
      .tab:hover {
        color: #333;
        background: #f8f9fa;
      }
      
      .tab.active {
        color: #007bff;
        border-bottom-color: #007bff;
      }
      
      .hidden { 
        display: none; 
      }
      
      #submit-btn {
        background: #4f46e5;
        color: white;
        padding: 12px 24px;
        border: none;
        border-radius: 6px;
        cursor: pointer;
        margin-top: 16px;
      }
      
      #submit-btn:disabled {
        background: #9ca3af;
        cursor: not-allowed;
      }
    </style>
  </head>
  <body>
    <h1>Payment Form</h1>
    <div class="payment-container">
      <div class="tabs">
        <button class="tab active" data-method="card">Payment Card</button>
        <button class="tab" data-method="ach">Bank Debit</button>
      </div>
      <div class="form-content">
        <div id="pay-component-1"></div>
        <button id="submit-btn" class="hidden">Process Payment</button>
      </div>
    </div>
    
    <script src="https://embedded-component-sandbox.payabli.com/component.js" data-test></script>
    <script>
      let payComponent;
      
      const cardConfig = {
        type: "methodEmbedded",
        rootContainer: "pay-component-1",
        token: "your-public-api-token",
        entryPoint: "your-entry-point",
        defaultOpen: "card",
        temporaryToken: true,
        card: {
          enabled: true,
          amex: true,
          discover: true,
          visa: true,
          mastercard: true,
          jcb: true,
          diners: true,
          inputs: {
            cardHolderName: { 
              label: "NAME ON CARD", 
              size: 12, 
              row: 0, 
              order: 0 
            },
            cardNumber: { 
              label: "CARD NUMBER", 
              size: 6, 
              row: 1, 
              order: 0 
            },
            cardExpirationDate: { 
              label: "EXPIRATION", 
              size: 6, 
              row: 1, 
              order: 1 
            },
            cardCvv: {
              label: "CVV",
              size: 6,
              row: 2,
              order: 0
            },
            cardZipcode: {
              label: "ZIP CODE",
              size: 6,
              row: 2,
              order: 1
            }
          }
        },
        functionCallBackSuccess: function (response) {
          console.log(response);
          switch (response.responseText) {
            case "Success":
              // Temporary token was successfully created
              // The referenceId is the temporary token to use in backend API calls
              const tempToken = response.responseData.referenceId;
              alert(`Temporary token created: ${tempToken}`);
              
              // In a real application, you would send this token to your backend
              // to either:
              // 1. Convert to permanent token via TokenStorage/add with temporary=false
              // 2. Use directly in MoneyIn/getpaid as storedMethodId
              break;
            case "Declined":
              alert(`Declined: ${response.responseData.resultText}`);
              payComponent.payabliExec("reinit");
              break;
            default:
              alert(`Error: ${response.responseText}`);
              payComponent.payabliExec("reinit");
              break;
          }
        },
        functionCallBackError: function(errors) {
          console.log("Token creation error:", errors);
          alert("Token creation error occurred");
          payComponent.payabliExec("reinit");
        },
        functionCallBackReady: function(data) {
          const btn = document.getElementById("submit-btn");
          if (data[1] === true) {
            btn.classList.remove("hidden");
          } else {
            btn.classList.add("hidden");
          }
        }
      };
    </script>
  </body>
  </html>
  ```

  /// Configure ACH Payment Method

  Create the configuration object for ACH payments with `temporaryToken: true`.
  The `token` must be a **public API token**.

  ```html focus=158-241
  <!DOCTYPE html>
  <html>
  <head>
    <meta charset="UTF-8">
    <title>Payabli Integration</title>
    <style>
      .tabs {
        display: flex;
        border-bottom: 1px solid #e5e5e5;
        margin-bottom: 20px;
      }
      
      .tab {
        flex: 1;
        padding: 16px 24px;
        text-align: center;
        cursor: pointer;
        background: white;
        border: none;
        border-bottom: 2px solid transparent;
        transition: all 0.2s ease;
      }
      
      .tab:hover {
        color: #333;
        background: #f8f9fa;
      }
      
      .tab.active {
        color: #007bff;
        border-bottom-color: #007bff;
      }
      
      .hidden { 
        display: none; 
      }
      
      #submit-btn {
        background: #4f46e5;
        color: white;
        padding: 12px 24px;
        border: none;
        border-radius: 6px;
        cursor: pointer;
        margin-top: 16px;
      }
      
      #submit-btn:disabled {
        background: #9ca3af;
        cursor: not-allowed;
      }
    </style>
  </head>
  <body>
    <h1>Payment Form</h1>
    <div class="payment-container">
      <div class="tabs">
        <button class="tab active" data-method="card">Payment Card</button>
        <button class="tab" data-method="ach">Bank Debit</button>
      </div>
      <div class="form-content">
        <div id="pay-component-1"></div>
        <button id="submit-btn" class="hidden">Process Payment</button>
      </div>
    </div>
    
    <script src="https://embedded-component-sandbox.payabli.com/component.js" data-test></script>
    <script>
      let payComponent;
      
      const cardConfig = {
        type: "methodEmbedded",
        rootContainer: "pay-component-1",
        token: "your-public-api-token",
        entryPoint: "your-entry-point",
        defaultOpen: "card",
        temporaryToken: false,
        card: {
          enabled: true,
          amex: true,
          discover: true,
          visa: true,
          mastercard: true,
          jcb: true,
          diners: true,
          inputs: {
            cardHolderName: { 
              label: "NAME ON CARD", 
              size: 12, 
              row: 0, 
              order: 0 
            },
            cardNumber: { 
              label: "CARD NUMBER", 
              size: 6, 
              row: 1, 
              order: 0 
            },
            cardExpirationDate: { 
              label: "EXPIRATION", 
              size: 6, 
              row: 1, 
              order: 1 
            },
            cardCvv: {
              label: "CVV",
              size: 6,
              row: 2,
              order: 0
            },
            cardZipcode: {
              label: "ZIP CODE",
              size: 6,
              row: 2,
              order: 1
            }
          }
        },
        functionCallBackSuccess: function (response) {
          // This callback covers both 2XX and 4XX responses
          console.log(response);
          switch (response.responseText) {
            case "Success":
              // Tokenization was successful
              alert(`Success: ${response.responseData.resultText}`);
              break;
            case "Declined":
              // Tokenization failed due to processor decline or validation errors
              // Recommend reinitialization of the component so that the user can try again
              // with different card data
              alert(`Declined: ${response.responseData.resultText}`);
              payComponent.payabliExec("reinit");
              break;
            default:
              // Other response text. These are normally errors with Payabli internal validations
              // before processor engagement
              // We recommend reinitializing the component.
              // If the problem persists, contact Payabli to help debug
              alert(`Error: ${response.responseText}`);
              payComponent.payabliExec("reinit");
              break;
          }
        },
        functionCallBackError: function(errors) {
          console.log("Payment error:", errors);
          alert("Payment processing error occurred");
          payComponent.payabliExec("reinit");
        },
        functionCallBackReady: function(data) {
          const btn = document.getElementById("submit-btn");
          if (data[1] === true) {
            btn.classList.remove("hidden");
          } else {
            btn.classList.add("hidden");
          }
        }
      };
      
      const achConfig = {
        type: "methodEmbedded",
        rootContainer: "pay-component-1",
        token: "your-public-api-token",
        entryPoint: "your-entry-point",
        defaultOpen: "ach",
        temporaryToken: true,
        ach: {
          enabled: true,
          checking: true,
          savings: true,
          inputs: {
            achAccountHolderName: {
              label: "ACCOUNT HOLDER NAME",
              placeholder: "Account Holder Name",
              floating: false,
              size: 6,
              row: 0,
              order: 0
            },
            achRouting: {
              label: "ROUTING NUMBER",
              placeholder: "123456789",
              floating: false,
              size: 6,
              row: 1,
              order: 0
            },
            achAccount: {
              label: "ACCOUNT NUMBER",
              placeholder: "Account Number",
              floating: false,
              size: 6,
              row: 1,
              order: 1
            },
            achAccountType: {
              label: "ACCOUNT TYPE",
              floating: false,
              size: 6,
              row: 0,
              order: 1
            }
          }
        },
        functionCallBackSuccess: function (response) {
          // This callback covers both 2XX and 4XX responses
          console.log(response);
          switch (response.responseText) {
            case "Success":
              // Tokenization was successful
              alert(`Success: ${response.responseData.resultText}`);
              break;
            case "Declined":
              // Tokenization failed due to processor decline or validation errors
              // Recommend reinitialization of the component so that the user can try again
              // with different card data
              alert(`Declined: ${response.responseData.resultText}`);
              payComponent.payabliExec("reinit");
              break;
            default:
              // Other response text. These are normally errors with Payabli internal validations
              // before processor engagement
              // We recommend reinitializing the component.
              // If the problem persists, contact Payabli to help debug
              alert(`Error: ${response.responseText}`);
              payComponent.payabliExec("reinit");
              break;
          }
        },
        functionCallBackError: function(errors) {
          console.log("Payment error:", errors);
          alert("Payment processing error occurred");
          payComponent.payabliExec("reinit");
        },
        functionCallBackReady: function(data) {
          const btn = document.getElementById("submit-btn");
          if (data[1] === true) {
            btn.classList.remove("hidden");
          } else {
            btn.classList.add("hidden");
          }
        }
      };
    </script>
  </body>
  </html>
  ```

  /// Add Tab Switching Logic

  Add JavaScript code for the tabs. The code handles reinitializing the component when users change payment methods.

  ```html focus=226-241
  <!DOCTYPE html>
  <html>
  <head>
    <meta charset="UTF-8">
    <title>Payabli Integration</title>
    <style>
      .tabs {
        display: flex;
        border-bottom: 1px solid #e5e5e5;
        margin-bottom: 20px;
      }
      
      .tab {
        flex: 1;
        padding: 16px 24px;
        text-align: center;
        cursor: pointer;
        background: white;
        border: none;
        border-bottom: 2px solid transparent;
        transition: all 0.2s ease;
      }
      
      .tab:hover {
        color: #333;
        background: #f8f9fa;
      }
      
      .tab.active {
        color: #007bff;
        border-bottom-color: #007bff;
      }
      
      .hidden { 
        display: none; 
      }
      
      #submit-btn {
        background: #4f46e5;
        color: white;
        padding: 12px 24px;
        border: none;
        border-radius: 6px;
        cursor: pointer;
        margin-top: 16px;
      }
      
      #submit-btn:disabled {
        background: #9ca3af;
        cursor: not-allowed;
      }
    </style>
  </head>
  <body>
    <h1>Payment Form</h1>
    <div class="payment-container">
      <div class="tabs">
        <button class="tab active" data-method="card">Payment Card</button>
        <button class="tab" data-method="ach">Bank Debit</button>
      </div>
      <div class="form-content">
        <div id="pay-component-1"></div>
        <button id="submit-btn" class="hidden">Process Payment</button>
      </div>
    </div>
    
    <script src="https://embedded-component-sandbox.payabli.com/component.js" data-test></script>
    <script>
      let payComponent;
      
      const cardConfig = {
        type: "methodEmbedded",
        rootContainer: "pay-component-1",
        token: "your-public-api-token",
        entryPoint: "your-entry-point",
        defaultOpen: "card",
        temporaryToken: false,
        card: {
          enabled: true,
          amex: true,
          discover: true,
          visa: true,
          mastercard: true,
          jcb: true,
          diners: true,
          inputs: {
            cardHolderName: { 
              label: "NAME ON CARD", 
              size: 12, 
              row: 0, 
              order: 0 
            },
            cardNumber: { 
              label: "CARD NUMBER", 
              size: 6, 
              row: 1, 
              order: 0 
            },
            cardExpirationDate: { 
              label: "EXPIRATION", 
              size: 6, 
              row: 1, 
              order: 1 
            },
            cardCvv: {
              label: "CVV",
              size: 6,
              row: 2,
              order: 0
            },
            cardZipcode: {
              label: "ZIP CODE",
              size: 6,
              row: 2,
              order: 1
            }
          }
        },
        functionCallBackSuccess: function (response) {
          console.log(response);
          switch (response.responseText) {
            case "Success":
              alert(`Success: ${response.responseData.resultText}`);
              break;
            case "Declined":
              alert(`Declined: ${response.responseData.resultText}`);
              payComponent.payabliExec("reinit");
              break;
            default:
              alert(`Error: ${response.responseText}`);
              payComponent.payabliExec("reinit");
              break;
          }
        },
        functionCallBackError: function(errors) {
          console.log("Payment error:", errors);
          alert("Payment processing error occurred");
          payComponent.payabliExec("reinit");
        },
        functionCallBackReady: function(data) {
          const btn = document.getElementById("submit-btn");
          if (data[1] === true) {
            btn.classList.remove("hidden");
          } else {
            btn.classList.add("hidden");
          }
        }
      };
      
      const achConfig = {
        type: "methodEmbedded",
        rootContainer: "pay-component-1",
        token: "your-public-api-token",
        entryPoint: "your-entry-point",
        defaultOpen: "ach",
        temporaryToken: false,
        ach: {
          enabled: true,
          checking: true,
          savings: true,
          inputs: {
            achAccountHolderName: {
              label: "ACCOUNT HOLDER NAME",
              placeholder: "Account Holder Name",
              floating: false,
              size: 6,
              row: 0,
              order: 0
            },
            achRouting: {
              label: "ROUTING NUMBER",
              placeholder: "123456789",
              floating: false,
              size: 6,
              row: 1,
              order: 0
            },
            achAccount: {
              label: "ACCOUNT NUMBER",
              placeholder: "Account Number",
              floating: false,
              size: 6,
              row: 1,
              order: 1
            },
            achAccountType: {
              label: "ACCOUNT TYPE",
              floating: false,
              size: 6,
              row: 0,
              order: 1
            }
          }
        },
        functionCallBackSuccess: function (response) {
          console.log(response);
          switch (response.responseText) {
            case "Success":
              alert(`Success: ${response.responseData.resultText}`);
              break;
            case "Declined":
              alert(`Declined: ${response.responseData.resultText}`);
              payComponent.payabliExec("reinit");
              break;
            default:
              alert(`Error: ${response.responseText}`);
              payComponent.payabliExec("reinit");
              break;
          }
        },
        functionCallBackError: function(errors) {
          console.log("Payment error:", errors);
          alert("Payment processing error occurred");
          payComponent.payabliExec("reinit");
        },
        functionCallBackReady: function(data) {
          const btn = document.getElementById("submit-btn");
          if (data[1] === true) {
            btn.classList.remove("hidden");
          } else {
            btn.classList.add("hidden");
          }
        }
      };
      
      // Tab switching
      document.querySelectorAll('.tab').forEach(tab => {
        tab.addEventListener('click', function() {
          const method = this.dataset.method;
          
          // Update active tab
          document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
          this.classList.add('active');
          
          // Create new component with appropriate config
          if (method === 'card') {
            payComponent = new PayabliComponent(cardConfig);
          } else if (method === 'ach') {
            payComponent = new PayabliComponent(achConfig);
          }
        });
      });
    </script>
  </body>
  </html>
  ```

  /// Initialize and Execute Token Generation

  Use the `payabliExec('method')` function to trigger temporary token generation.
  This function generates a secure temporary token for the payment method entered into the embedded component.
  For more information on using temporary tokens, see [Extend embedded components with the temporary token flow](/guides/platform-developer-tokenization-temp-flow).

  ```html focus=245-257
  <!DOCTYPE html>
  <html>
  <head>
    <meta charset="UTF-8">
    <title>Payabli Integration</title>
    <style>
      .tabs {
        display: flex;
        border-bottom: 1px solid #e5e5e5;
        margin-bottom: 20px;
      }
      
      .tab {
        flex: 1;
        padding: 16px 24px;
        text-align: center;
        cursor: pointer;
        background: white;
        border: none;
        border-bottom: 2px solid transparent;
        transition: all 0.2s ease;
      }
      
      .tab:hover {
        color: #333;
        background: #f8f9fa;
      }
      
      .tab.active {
        color: #007bff;
        border-bottom-color: #007bff;
      }
      
      .hidden { 
        display: none; 
      }
      
      #submit-btn {
        background: #4f46e5;
        color: white;
        padding: 12px 24px;
        border: none;
        border-radius: 6px;
        cursor: pointer;
        margin-top: 16px;
      }
      
      #submit-btn:disabled {
        background: #9ca3af;
        cursor: not-allowed;
      }
    </style>
  </head>
  <body>
    <h1>Payment Form</h1>  
    <p>Enter your payment information to generate a temporary token:</p>
    <div class="payment-container">
      <div class="tabs">
        <button class="tab active" data-method="card">Payment Card</button>
        <button class="tab" data-method="ach">Bank Debit</button>
      </div>
      <div class="form-content">
        <div id="pay-component-1"></div>
        <button id="submit-btn" class="hidden">Process Payment</button>
      </div>
    </div>
    
    <script src="https://embedded-component-sandbox.payabli.com/component.js" data-test></script>
    <script>
      let payComponent;
      
      const cardConfig = {
        type: "methodEmbedded",
        rootContainer: "pay-component-1",
        token: "your-public-api-token",
        entryPoint: "your-entry-point",
        defaultOpen: "card",
        temporaryToken: false,
        card: {
          enabled: true,
          amex: true,
          discover: true,
          visa: true,
          mastercard: true,
          jcb: true,
          diners: true,
          inputs: {
            cardHolderName: { 
              label: "NAME ON CARD", 
              size: 12, 
              row: 0, 
              order: 0 
            },
            cardNumber: { 
              label: "CARD NUMBER", 
              size: 6, 
              row: 1, 
              order: 0 
            },
            cardExpirationDate: { 
              label: "EXPIRATION", 
              size: 6, 
              row: 1, 
              order: 1 
            },
            cardCvv: {
              label: "CVV",
              size: 6,
              row: 2,
              order: 0
            },
            cardZipcode: {
              label: "ZIP CODE",
              size: 6,
              row: 2,
              order: 1
            }
          }
        },
        functionCallBackSuccess: function (response) {
          console.log(response);
          switch (response.responseText) {
            case "Success":
              alert(`Success: ${response.responseData.resultText}`);
              break;
            case "Declined":
              alert(`Declined: ${response.responseData.resultText}`);
              payComponent.payabliExec("reinit");
              break;
            default:
              alert(`Error: ${response.responseText}`);
              payComponent.payabliExec("reinit");
              break;
          }
        },
        functionCallBackError: function(errors) {
          console.log("Payment error:", errors);
          alert("Payment processing error occurred");
          payComponent.payabliExec("reinit");
        },
        functionCallBackReady: function(data) {
          const btn = document.getElementById("submit-btn");
          if (data[1] === true) {
            btn.classList.remove("hidden");
          } else {
            btn.classList.add("hidden");
          }
        }
      };
      
      const achConfig = {
        type: "methodEmbedded",
        rootContainer: "pay-component-1",
        token: "your-public-api-token",
        entryPoint: "your-entry-point",
        defaultOpen: "ach",
        temporaryToken: false,
        ach: {
          enabled: true,
          checking: true,
          savings: true,
          inputs: {
            achAccountHolderName: {
              label: "ACCOUNT HOLDER NAME",
              placeholder: "Account Holder Name",
              floating: false,
              size: 6,
              row: 0,
              order: 0
            },
            achRouting: {
              label: "ROUTING NUMBER",
              placeholder: "123456789",
              floating: false,
              size: 6,
              row: 1,
              order: 0
            },
            achAccount: {
              label: "ACCOUNT NUMBER",
              placeholder: "Account Number",
              floating: false,
              size: 6,
              row: 1,
              order: 1
            },
            achAccountType: {
              label: "ACCOUNT TYPE",
              floating: false,
              size: 6,
              row: 0,
              order: 1
            }
          }
        },
        functionCallBackSuccess: function (response) {
          console.log(response);
          switch (response.responseText) {
            case "Success":
              alert(`Success: ${response.responseData.resultText}`);
              break;
            case "Declined":
              alert(`Declined: ${response.responseData.resultText}`);
              payComponent.payabliExec("reinit");
              break;
            default:
              alert(`Error: ${response.responseText}`);
              payComponent.payabliExec("reinit");
              break;
          }
        },
        functionCallBackError: function(errors) {
          console.log("Payment error:", errors);
          alert("Payment processing error occurred");
          payComponent.payabliExec("reinit");
        },
        functionCallBackReady: function(data) {
          const btn = document.getElementById("submit-btn");
          if (data[1] === true) {
            btn.classList.remove("hidden");
          } else {
            btn.classList.add("hidden");
          }
        }
      };
      
      // Tab switching
      document.querySelectorAll('.tab').forEach(tab => {
        tab.addEventListener('click', function() {
          const method = this.dataset.method;
          
          // Update active tab
          document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
          this.classList.add('active');
          
          // Create new component with appropriate config
          if (method === 'card') {
            payComponent = new PayabliComponent(cardConfig);
          } else if (method === 'ach') {
            payComponent = new PayabliComponent(achConfig);
          }
        });
      });
      
      // Initialize the Payabli component
      payComponent = new PayabliComponent(cardConfig);
      
      // Handle token generation - no payment details needed for temporary token
      document.getElementById("submit-btn").addEventListener("click", function() {
      // Call method without payment details to generate temporary token
      payComponent.payabliExec('method', {
        customerData: {
          firstName: "John",
          lastName: "Doe",
          billingEmail: "john.doe@example.com"
        }
      });
    </script>
  </body>
  </html>
  ```
</div>

### Configuration reference

These are the configuration parameters available for the EmbeddedMethod component.
If you need to pass more than data than what's supported, consider using the temporary token flow.
See [Temporary Token Flow](/guides/platform-developer-tokenization-temp-flow) for more information.

<ParamField path="type" type="string" required>
  This value determines the type of embedded component to render.\
  Accepted values are: `methodEmbedded`, `methodLightbox`, `vterminal`, or `expressCheckout`.\
  For the EmbeddedMethod UI, this value is `methodEmbedded`.
  See the [Embedded Components Overview](/guides/pay-in-components-overview) for more information on other component types.
</ParamField>

<ParamField path="rootContainer" type="string" required>
  Container ID used for the component.
</ParamField>

<ParamField path="defaultOpen" type="string">
  Sets the default payment method that's shown. Accepted values are: `card` or `ach`.
</ParamField>

<ParamField path="hideComponent" type="boolean" default="false">
  When true the component is hidden when it's instanced.
</ParamField>

<ParamField path="token" type="string" required>
  API token for authentication. This should be a **public** API token, as described [here](/developers/api-reference/api-overview#authentication#organization-token-most-common).
</ParamField>

<ParamField path="forceCustomerCreation" type="boolean" default="true">
  When `true`, the component uses the `customerData` object to create a new customer record.
  When `temporaryToken` is `true` and `forceCustomerCreation` is `false`, the component doesn't create a new customer record.
  See [Temporary Token Flow](/guides/platform-developer-tokenization-temp-flow#disable-customer-creation) for more information.
</ParamField>

<ParamField path="customCssUrl" type="string">
  Complete URL of a custom CSS stylesheet to use with the component.
</ParamField>

<ParamField path="clearFormAfterSubmit" type="boolean" default="true">
  When `true`, the entered values on the form are cleared when submitted.
</ParamField>

<ParamField path="temporaryToken" type="boolean" default="true">
  When `true`, the token created for the payment is temporary. Set this parameter to false to create a storedMethodId and save the payment profile.
</ParamField>

<ParamField path="showPopoverError" type="boolean" default="true">
  When `false`, the validation error appears below the field instead of above it in a popover.
</ParamField>

<ParamField path="entryPoint" type="string">
  When the API token belongs to an organization, the entrypoint name identifies the target paypoint (merchant).
</ParamField>

<ParamField path="card" type="object" required>
  `cardService` object used to configure accepted card types.

  <Expandable title="properties">
    <ParamField path="enabled" type="boolean">
      Enable/disable card option.
    </ParamField>

    <ParamField path="amex" type="boolean">
      Enable/disable acceptance of American Express cards.
    </ParamField>

    <ParamField path="discover" type="boolean">
      Enable/disable acceptance of Discover cards.
    </ParamField>

    <ParamField path="visa" type="boolean">
      Enable/disable acceptance of Visa cards.
    </ParamField>

    <ParamField path="mastercard" type="boolean">
      Enable/disable acceptance of MasterCard cards.
    </ParamField>

    <ParamField path="diners" type="boolean">
      Enable/disable acceptance of Diner's Club cards.
    </ParamField>

    <ParamField path="jcb" type="boolean">
      Enable/disable acceptance of JCB cards.
    </ParamField>

    <ParamField path="inputs" type="object">
      Card input fields descriptors. This object applies only to the EmbeddedMethod UI component.

      <Expandable title="properties">
        <ParamField path="cardHolderName" type="object">
          Optional, but *strongly recommended*. Descriptor object for input field.
        </ParamField>

        <ParamField path="cardNumber" type="object" required>
          Descriptor object for input field.
        </ParamField>

        <ParamField path="cardExpirationDate" type="object" required>
          Descriptor object for input field.
        </ParamField>

        <ParamField path="cardCvv" type="object" required>
          Descriptor object for input field.
        </ParamField>

        <ParamField path="cardZipcode" type="object">
          Optional, but *strongly recommended*. Descriptor object for input field.
        </ParamField>
      </Expandable>
    </ParamField>
  </Expandable>
</ParamField>

<ParamField path="ach" type="object" required>
  `achService` object used to configure accepted ACH types.

  <Expandable title="properties">
    <ParamField path="enabled" type="boolean">
      Enable/disable ACH option.
    </ParamField>

    <ParamField path="checking" type="boolean">
      Enable/disable acceptance of Checking account.
    </ParamField>

    <ParamField path="savings" type="boolean">
      Enable/disable acceptance of Savings account.
    </ParamField>

    <ParamField path="achValidation" type="boolean" default="false">
      When set to true, the embedded component will validate ACH account and routing numbers in real time.
      This is an add-on feature. Contact the Payabli team for more information.
    </ParamField>

    <ParamField path="inputs" type="object">
      ACH input field descriptors. This only applies to the EmbeddedMethod UI component.

      <Expandable title="properties">
        <ParamField path="achAccountHolderName" type="object" required>
          Required. Descriptor object for input field.
        </ParamField>

        <ParamField path="achAccountType" type="object" required>
          Required. Descriptor object for input field.
        </ParamField>

        <ParamField path="achRouting" type="object" required>
          Required. Descriptor object for input field. Use the
          `confirm` input descriptor to add matching validation to this field. See [Style Individual Fields](/guides/pay-in-components-overview#style-individual-fields) for more.
        </ParamField>

        <ParamField path="achAccount" type="object" required>
          Required. Descriptor object for input field. Use the
          `confirm` input descriptor to add matching validation to this field. See [Style Individual Fields](/guides/pay-in-components-overview#style-individual-fields) for more.
        </ParamField>
      </Expandable>
    </ParamField>
  </Expandable>
</ParamField>

<ParamField path="rdc" type="object" required>
  `rdcService` object used to configure accepted RDC types.

  <Expandable title="properties">
    <ParamField path="enabled" type="boolean">
      Enable/disable RDC option.
    </ParamField>

    <ParamField path="amount" type="number">
      Amount to collect via RDC.
    </ParamField>

    <ParamField path="inputs" type="object">
      RDC input field descriptors.

      <Expandable title="properties">
        <ParamField path="rdcAccountHolderName" type="object">
          Descriptor object for input field.
        </ParamField>

        <ParamField path="rdcAmount" type="object">
          Descriptor object for input field.
        </ParamField>
      </Expandable>
    </ParamField>
  </Expandable>
</ParamField>

<ParamField path="paymentMethod" type="object" required>
  `paymentMethod` object with data related to the payment method. **Required when saving a payment method or executing a payment**. Can be passed to the component via payabliExec method.
</ParamField>

<ParamField path="customerData" type="object" required>
  Customer Object with data related to customer. Can be passed to the component as a parameter with the `payabliExec` method. **Required when saving a payment method**. Which fields are required depends on whether the paypoint has custom identifiers. If you aren't using custom identifiers, then you must include at least one of these values: `firstname` and `lastname`, `email`, or `customerId`.
</ParamField>

<ParamField path="paymentDetails" type="object" required>
  `paymentDetails` object with data related to the payment. **Required to save a payment method**. Can be passed to the component via payabliExec method.
</ParamField>

<ParamField path="fallbackAuth" type="boolean | null" default="false">
  When `true`, if tokenization fails, Payabli will attempt an authorization transaction to request a permanent token for the card. If the authorization is successful, the card will be tokenized and the authorization will be voided automatically.
</ParamField>

<ParamField path="fallbackAuthAmount" type="number | null" default="1.00">
  The amount for the `fallbackAuth` transaction. Defaults to one dollar.
</ParamField>

<ParamField path="functionCallBackSuccess" type="function">
  The callback function called when the component executes successfully.
</ParamField>

<ParamField path="functionCallBackError" type="function">
  The callback function called when the component receives an error. See [functionCallBackError response](#functioncallbackerror-response) in the next section for a complete reference.
</ParamField>

<ParamField path="functionCallBackReady" type="function">
  The callback function called when the component's status changes. Used to poll the form's completeness before showing the submit button.
</ParamField>

## Response

The embedded component returns a response object to the callback functions defined in the configuration.
The response object contains the result of the transaction (success, declined, or error) and details about the transaction.

### Response examples

Click the tab to see an example response returned by the embedded component for each result.

<CodeBlocks>
  ```js Payment success 
  {
    responseText: "Success",
    responseData: {
      authCode: "123456",
      referenceId: "40-692c62895d1541d28c0bf77b275a26e4",
      resultCode: 1,
      resultText: "Approved",
      avsResponseText: "",
      cvvResponseText: "",
      customerId: 706,
      methodReferenceId: null
    }
  }
  ```

  ```js Payment decline
  {
    responseText: "Declined",
    responseData: {
      authCode: null,
      referenceId: "40-2c437c3dcdc242bea96f52bdf42d2eeb",
      resultCode: 2,
      resultText: "200: Decline. Generally insufficient funds or incorrect card data supplied, for example, expiry date or security code.. DECLINE",
      avsResponseText: "",
      cvvResponseText: "",
      customerId: 706,
      methodReferenceId: null
    }
  }
  ```

  ```js Stored method success
  {
    responseText: "Success",
    responseData: {
      referenceId: "187-c5892026d9f345ffa63bf909d574fe92",
      resultCode: 1,
      resultText: "Added",
      customerId: 1636,
      methodReferenceId: "187-c5892026d9f345ffa63bf909d574fe92"
    }
  }
  ```

  ```js Stored method decline
  {
    responseText: "Declined",
    responseData: {
      referenceId: "187-d2a29970fa604edba5a6dbec67ace3ae",
      resultCode: 2,
      resultText: "200: Transaction was declined by processor.. DECLINE",
      customerId: 1636,
      methodReferenceId: "187-d2a29970fa604edba5a6dbec67ace3ae"
    }
  }
  ```
</CodeBlocks>

### Response reference

The response object passed to a callback function has the following structure:

<ParamField path="responseText" type="string">
  "Success" or "Declined"
</ParamField>

<ParamField path="responseData" type="object">
  Container for response details.

  <Expandable title="properties">
    <ParamField path="responseData.AuthCode" type="string">
      Authorization code for payments. This field has a value of `null` for saved payment methods.
    </ParamField>

    <ParamField path="responseData.ReferenceId" type="string">
      Identifier for the transaction (for payments) or the stored payment method (for save payment method).
    </ParamField>

    <ParamField path="responseData.ResultCode" type="integer">
      Result of operation. 1 is success, 2 is declined, and 3 is error.
    </ParamField>

    <ParamField path="responseData.ResultText" type="string">
      Message related the result. If the operation was successful, it returns "Added"/"Approved". If there was an error, it returns error details.
    </ParamField>

    <ParamField path="responseData.AvsResponseText" type="string">
      Result of address validation for card transactions. This field is an empty string when processing ACH transactions. This field doesn't exist when saving payment methods.
    </ParamField>

    <ParamField path="responseData.CvvResponseText" type="string">
      Result of CVV validation for card transactions. This field is an empty string when processing ACH transactions. This field doesn't exist when saving payment methods.
    </ParamField>

    <ParamField path="responseData.CustomerId" type="integer">
      ID for the customer owner of payment or saved payment method.
    </ParamField>

    <ParamField path="responseData.methodReferenceId" type="string">
      Identifier for stored payment method for saved payment methods.
      This field has a value of `null` for payment transactions.
      The `methodReferenceId` is used as the `storedMethodId` in other operations.
      See [Handling responses and errors](/guides/pay-in-components-overview#handling-responses-and-errors) for more.
    </ParamField>
  </Expandable>
</ParamField>

### `functionCallBackError` response

The `functionCallBackError` function is called when the component can't validate the payment information before submitting it to Payabli's API.
The response object passed to `functionCallBackError` contains an array with codes, keys, and descriptions of failed validations.
You can check the values in the array to offer your customized error message.

<div class="styled-table">
  <table id="responseerror">
    <thead>
      <tr>
        <th>
          Code
        </th>

        <th>
          Key
        </th>

        <th>
          Description
        </th>
      </tr>
    </thead>

    <tbody>
      <tr>
        <td>
          802
        </td>

        <td>
          paymentMethodsCardNumberError
        </td>

        <td>
          Error in Card number field
        </td>
      </tr>

      <tr>
        <td>
          803
        </td>

        <td>
          paymentMethodsCardExpirationDateError
        </td>

        <td>
          Error in Card Expiration field
        </td>
      </tr>

      <tr>
        <td>
          804
        </td>

        <td>
          paymentMethodsCardCvvError
        </td>

        <td>
          Error in CardCVV field
        </td>
      </tr>

      <tr>
        <td>
          805
        </td>

        <td>
          paymentMethodsCardZipcodeError
        </td>

        <td>
          Error in Card Zip code field
        </td>
      </tr>

      <tr>
        <td>
          901
        </td>

        <td>
          paymentMethodsAchAccountHolderNameError
        </td>

        <td>
          Error in ACH Holder field
        </td>
      </tr>

      <tr>
        <td>
          902
        </td>

        <td>
          paymentMethodsAchAccountTypeError
        </td>

        <td>
          Error in ACH Account type field
        </td>
      </tr>

      <tr>
        <td>
          903
        </td>

        <td>
          paymentMethodsAchRoutingError
        </td>

        <td>
          Error in ACH Routing field
        </td>
      </tr>

      <tr>
        <td>
          904
        </td>

        <td>
          paymentMethodsAchAccountError
        </td>

        <td>
          Error in ACH Account number field
        </td>
      </tr>
    </tbody>
  </table>
</div>

## Usage Flows

These flowcharts illustrate the path to making a payment or storing a payment method using an embedded component.

### Make a payment

To make a payment with an embedded component, your component configuration should contain `payabliExec(pay, parameters)`. In the `parameters` argument, include `customerData` and `paymentDetails` objects. When the payment is executed, the request returns response data.

*This flowchart explains the basic steps for the task. Hover over a step for more information.*

<div>
  <div>
    Run `payabliExec(pay, parameters)`
    <span>The action is set to `pay` here. Send the `paymentDetail` and `customerData` object in `parameters`.</span>
  </div>

  <div>
    →
  </div>

  <div>
    Payment executed
    <span>The transaction is executed and includes the data sent as parameters</span>
  </div>

  <div>
    →
  </div>

  <div>
    Response
  </div>
</div>

### Save a payment method

To save a payment method with an embedded component, your component configuration should contain `payabliExec(method, parameters)`. In the `parameters` argument, include `customerData` and `paymentDetails` objects. When the payment method is saved, the request returns response data.

*This flowchart explains the basic steps for the task. Hover over a step for more information.*

<div>
  <div>
    Run `payabliExec(method, parameters)`
    <span>The action is set to `method` here. Send the `paymentDetail` and `customerData` object in `parameters`.</span>
  </div>

  <div>
    →
  </div>

  <div>
    Payment method saved
    <span>The payment method is saved and includes the data sent as parameters</span>
  </div>

  <div>
    →
  </div>

  <div>
    Response
  </div>
</div>

### Save a payment method and make a payment

You can save a payment method and make a payment with the EmbeddedMethod UI component by writing a callback function to execute the payment after successfully saving the payment method.

To save a payment method and then execute a transaction with the saved payment method, your component configuration should contain `payabliExec(method, parameters)`. In the `parameters` argument, include the `customerData` and `paymentDetails` objects. When the payment method is saved, use a callback function to execute the transaction.

<Warning>
  Remember to never make payment transactions via client-side API requests. Your callback function should make the payment transaction using a server-side function.
</Warning>

*This flowchart explains the basic steps for the task. Hover over a step for more information.*

<div>
  <div>
    Run `payabliExec(method, parameters)`
    <span>Here, the action is set to `method`. Send the `paymentDetail` and `customerData` object in `parameters`.</span>
  </div>

  <div>
    →
  </div>

  <div>
    Payment method saved
    <span>The payment method is saved and includes the data sent as parameters. An ID for the payment method is returned, which is then used to make transactions.</span>
  </div>

  <div>
    →
  </div>

  <div>
    Callback function
    <span>Use a callback function to send a transaction that uses the new payment method.</span>
  </div>

  <div>
    →
  </div>

  <div>
    Response
  </div>
</div>

## Related resources

See these related resources to help you get the most out of Payabli.

<AccordionGroup>
  <Accordion title="Advanced topics">
    * **[Embedded components framework integrations](/guides/pay-in-developer-components-frameworks)** - Learn how to use Payabli's embedded components with front-end frameworks like React and Vue
    * **[Temporary token example app (for developers)](/guides/platform-tokenization-temp-token-app)** - Go through a guided checkout experience using the temporary token flow
    * **[Extend embedded components with the temporary token flow (for developers)](/guides/platform-developer-tokenization-temp-flow)** - Use the temporary token flow with embedded components to have complete control over user transaction experience without expanding PCI scope
  </Accordion>

  <Accordion title="Related topics">
    * **[Embedded components overview](/guides/pay-in-components-overview)** - Learn how to use Payabli's embedded components to create customized checkout experiences without handling sensitive payment information yourself
  </Accordion>
</AccordionGroup>