Freedom to Design

Prerequisites

For Sandbox (UAT) Users should be onboarded on iPOSpays sandbox(UAT) environment as a merchant and have a valid TPN.

For Production (Live) Users should be onboarded on iPOSpays production environment as a merchant and have a valid TPN.

No TPN?

If you don't have a TPN, contact your ISO or devsupport@dejavoo.io.

Scope

FreedomToDesign handles data collection and tokenization only. It's not a complete payments API — pair it with the iPOS Transact API to process transactions.

Localhost Restriction

As per PCI compliance, requests from localhost are not allowed. To enable it for testing, contact ISV Sales or support@dejavoo.io.

Get Started

1Login to your merchant account and go to settings.
2Under Generate Ecom/TOP Merchant Keys section select TPN and Generate Token
3Under Whitelisted Domain add the domain of your site in which you want to accept payments.

Watch This Video for a Visual Walkthrough of the Steps

Now you have everything to setup your payment form.

Setting Up Your Payment Form

Freedom to design supports card payments and Google Pay.

Card

Follow the steps below to accept card payments

  • Open your website's entry file (index.html, app.component, or app.jsx) in a text editor.
  • Copy and paste the code from the panel into your project and run it.
  • Use the generated token inside "security_key."

Using the Payment Token ID

  • When the customer clicks the payment button, FreedomToDesign generates a unique paymentTokenId (e.g., 65564fda-9c7e-46fd-9eca-40caff6e53c6). This token is required to complete a transaction through the iPOS Transact API.

  • The paymentTokenId is single-use and expires after 24 hours if not used. When you send this token to the iPOS Transact API in a $0 Pre-Auth transaction request, the system returns a Card Token.

The Card Token is reusable and can be used for future transactions — simply set the cardToken to true when submitting the request via the iPOS Transact API

Expires in 24h

This payment token can only be used once and will expire after 24 hours if it is not used at all.

index.html
<!DOCTYPE html>
<html lang="en">

<head>
  <!-- Required meta tags -->
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <meta name="referrer" content="strict-origin-when-cross-origin" />
  <title>iPosPays Payment Form</title>


  <!-- Add defer to prevent blocking HTML rendering -->
  <script id="ftd" src="https://payment.ipospays.tech/ftd/v1/freedomtodesign.js" security_key="auth_token" defer></script>
</head>

<body>
  <form>
      <input id="ccnumber" />
      <input id="ccexpiry" />
      <input id="cccvv" />
      <input type="submit" id="payButton" />
  </form>


  <script>
      async function submitCardFunc(event) {
          event.preventDefault(); // Prevent default form submission
          try {
            const data_response = await postData();
            console.log("PaymentToken:", data_response.payment_token_id);
          } catch (error) {
            console.error("Error processing payment:", error);
          }
        }


        var payButton = document.getElementById("payButton");
        payButton.addEventListener("click", submitCardFunc);
  </script>
</body>

</html>
app.component.html
app.component.ts
app.component.html
<form (submit)="submitCardFunc($event)">
  <input id="ccnumber" />
  <input id="ccexpiry" />
  <input id="cccvv" />
  <input type="submit" id="payButton" />
</form>
app.component.ts
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';


declare let postData: () => Promise<any>; // Declare the postData function


@Component({
  selector: 'app-root',
  standalone: true,
  imports: [RouterOutlet],
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'] // Correctly linked to CSS
})
export class AppComponent {
  title = 'iPosPays Payment Form'; // Title for the payment form


  ngOnInit(): void {
    this.loadScript(); // Load external script on initialization
  }


  loadScript() {
    const script = document.createElement('script');
    script.src = 'https://payment.ipospays.tech/ftd/v1/freedomtodesign.js';
    script.id = 'ftd';
    script.setAttribute('security_key', 'auth_token');


    script.onload = () => {
      console.log('Script loaded successfully');
    };


    script.onerror = () => {
      console.error('Failed to load script');
    };


    document.body.appendChild(script);
  }


  async submitCardFunc(event: Event) {
    event.preventDefault(); // Prevent default form submission
    try {
      const response = await postData(); // Call postData function
      console.log('Payment Token:', response.payment_token_id); // Log the payment token
    } catch (error) {
      console.error('Error processing payment:', error); // Handle errors
    }
  }
}
app.jsx
app.js
import React, { useEffect, useState } from 'react';


const App = () => {
  const [postData, setPostData] = useState(null); // State to hold postData function
  const title = 'iPosPays Payment Form'; // Title for the payment form


  useEffect(() => {
    loadScript(); // Load the external script on component mount
  }, []);


  const loadScript = () => {
    const script = document.createElement('script');
    script.src = 'https://payment.ipospays.tech/ftd/v1/freedomtodesign.js';
    script.id = 'ftd';
    script.setAttribute('security_key', 'auth_token'); // Replace with your actual security key


    script.onload = () => {
      console.log('Script loaded successfully');
      // Check if postData is defined after the script loads
      if (typeof window.postData === 'function') {
        setPostData(() => window.postData); // Set postData in state
      } else {
        console.error('postData function is not defined'); // Log if postData is not available
      }
    };


    script.onerror = (error) => {
      console.error('Failed to load script', error);
      alert('Failed to load payment script. Please check your connection or the script URL.');
    };


    document.body.appendChild(script); // Append the script to the document
  };


  const submitCardFunc = async (event) => {
    event.preventDefault(); // Prevent default form submission
    if (!postData) {
      console.error('postData function is not available');
      return; // Exit if postData is not available
    }
    try {
      const response = await postData(); // Call postData function
      console.log('Payment Token:', response.payment_token_id); // Log the payment token
    } catch (error) {
      console.error('Error processing payment:', error); // Handle errors
    }
  };


  return (
    <div>
      <h1>{title}</h1>
      <form onSubmit={submitCardFunc}>
        <input id="ccnumber" placeholder="Card Number" />
        <input id="ccexpiry" placeholder="Expiry Date" />
        <input id="cccvv" placeholder="CVV" />
        <input type="submit" id="payButton" value="Pay" />
      </form>
    </div>
  );
};
export default App;

Google Pay

This section explains how to integrate Google Pay using the gpay.js service hosted on https://payment.ipospays.tech/ftd/v1/gpay.js

  • Open your website's index.html file in a text editor.
  • Copy and paste the following code into your text editor and run the program

Using the PaymentData

Once the user clicks the payment button, a unique paymentData is generated. This paymentData is required for initiating transactions via the iPOS Transact API.

index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Google Pay Integration</title>

    <!-- Load iPOSpays Google Pay SDK -->
    <script src="https://payment.ipospays.tech/ftd/v1/gpay-ftd.js"></script>
  </head>
  <body>
    <!-- Container where the Google Pay button will be rendered -->
    <div id="ipospays-gpay-btn"></div>

    <script>
      /**
       * Transaction information
       * - Defines purchase details like price, currency, and country
       */
      const transactionInfo = {
        countryCode: "US",          // 2-letter country code
        currencyCode: "USD",        // ISO currency code
        totalPriceStatus: "FINAL",  // Can be ESTIMATED or FINAL
        totalPrice: "12.00",        // Amount to be charged
        totalPriceLabel: "Total",   // Label displayed on checkout
      };

      /**
       * Merchant settings
       * - merchantId: Your assigned Google Pay Merchant ID
       * - Mode: "TEST" or "PRODUCTION"
       */
      const merchantId = "N/A"; // Replace with your actual Merchant ID in production
      const Mode = "TEST";      // Use TEST for sandbox integration

      /**
       * Google Pay button styling
       * - Customize the look & feel of the payment button
       */
      const buttonStyles = {
        buttonColor: "default",   // Options: default, black, white
        buttonType: "buy",        // Options: buy, checkout, plain, order
        buttonRadius: 4,          // Border radius in pixels
        buttonLocale: "en",       // Locale for button text
        buttonHeight: "40px",     // Height of the button
        buttonWidth: "240px",     // Width of the button
      };

      /**
       * Additional Google Pay fields
       * - Enable/disable checkout fields based on business needs
       */
      const goolePayFelids = {
        requestBillingAddress: isBillingRequired,    // true = require billing address
        requestPayerEmail: isPayerEmailRequired,     // true = require customer email
        requestPayerPhone: isPayerPhoneRequired,      // true = require customer phone
        requestShipping: isShippingRequired,         // true = require shipping address
      };

      /**
       * Callback function
       * - Receives payment token after customer authorizes Google Pay
       * - You must send this token securely to your backend
       */
      function getPaymentInfo(paymentData) {
        console.log("Received Payment Token (Raw):", paymentData);
        // TODO: Send `paymentData` to your server for processing
      }

      /**
       * Example: Update cart price dynamically
       * - Assumes `priceCart` is an input field in the page
       * - Keeps checkout price in sync with cart updates
       */
      updatePrice(priceCart.value);

      /**
       * Initialize Google Pay
       * - Renders Google Pay button
       * - Configures transaction info, merchant, mode, style, and fields
       */
      initializeGooglePay(transactionInfo, merchantId, Mode, buttonStyles, goolePayFelids);
    </script>
  </body>
</html>
app.component.html
app.component.ts
google-pay-ftd.component.html
<div id="ipospays-gpay-btn"></div>
google-pay-ftd.component.ts
import { Component, OnInit, OnDestroy } from '@angular/core';


declare let initializeGooglePay: (
 transactionInfo: any,
 merchantId: string,
 Mode: string,
 buttonStyles: any
) => Promise<any>;


@Component({
 selector: 'app-google-pay-ftd',
 standalone: true,
 templateUrl: './google-pay-ftd.component.html',
 styleUrls: ['./google-pay-ftd.component.css']
})
export class GooglePayFtdComponent implements OnInit, OnDestroy {
 title = 'Google Pay Integration';


 ngOnInit(): void {
   this.loadGooglePayScript();
   (window as any).getPaymentInfo = this.getPaymentInfo.bind(this); // Attach function to `window`
 }


 ngOnDestroy(): void {
   delete (window as any).getPaymentInfo; // Clean up when component is destroyed
 }


 loadGooglePayScript(): void {
   if (document.getElementById('gpayftd')) {
     console.log('Google Pay script is already loaded.');
     return;
   }


   const script = document.createElement('script');
   script.src = 'https://payment.ipospays.tech/ftd/v1/gpay.js';
   script.id = 'gpayftd';
   script.setAttribute('security_key', 'auth_token');

   script.onload = () => {
     console.log('Google Pay script loaded successfully');
     this.initializeGooglePay();
   };


   script.onerror = () => {
     console.error('Failed to load Google Pay script');
   };


   document.body.appendChild(script);
 }


 initializeGooglePay(): void {
   const transactionInfo = {
     countryCode: "US",
     currencyCode: "USD",
     totalPriceStatus: "FINAL",
     totalPrice: "12.00",
     totalPriceLabel: "Total"
   };


const goolePayFelids = {
      	requestBillingAddress: isBillingRequired, // true or false
           	requestPayerEmail: isPayerEmailRequired, // true or false
           	requestPayerPhone: isPayerPhoneRequired, // true or false
      	requestShipping: isShippingRequired, // true or false
      };


   const merchantId = "N/A";
   const Mode = "TEST";
   const buttonStyles = {
     buttonColor: "default",
     buttonType: "buy",
     buttonRadius: 4,
     buttonLocale: "en",
     buttonHeight: "40px",
     buttonWidth: "240px"
   };


   if (typeof initializeGooglePay === 'function') {
     initializeGooglePay(
       transactionInfo,
       merchantId,
       Mode,
       buttonStyles,
	  goolePayFelids
     );
   } else {
     console.error('initializeGooglePay function is not available.');
   }
 }


 getPaymentInfo(paymentData: any): void {
   console.log('Received Payment Token:', paymentData);
 }

Apple Pay

1Add the Apple Pay SDK

You need to include the iPOSpays Apple Pay SDK script on your page.

📌 This script provides the initializeApplePay() function that will render the Apple Pay button.

<script 
  src="https://payment.ipospays.tech/ftd/v1/ipospays-apple-pay-ftd.js" 
  id="applepayftd">
</script>
2Add a Button Container

Apple Pay needs a container div where the button will appear.

📌 The Apple Pay button will be automatically injected here by the SDK.

<div id="ipospays-apple-pay-button"></div>
3Configure Transaction Info

You must provide details about the transaction such as country, currency, and total price.

const transactionInfo = {
  countryCode: "US",         // ISO country code
  currencyCode: "USD",       // ISO currency code
  totalPriceStatus: "FINAL", // FINAL = exact price, ESTIMATED = may change
  totalPrice: "49.99",       // Total amount to charge
};
4Configure Button Styles

Customize the Apple Pay button appearance.

📌 Example: A black "Buy with Pay" button will be displayed.

const buttonStyles = {
  buttonColor: "black",   // black or white
  buttonType: "buy",      // buy, checkout, donate, etc.
  buttonRadius: "8px",    // corner radius
  buttonLocale: "en-US",  // locale for button label
  buttonHeight: "50px",   // height of the button
  buttonWidth: "100%",    // width of the button
};
5Configure Apple Pay Fields

Specify what extra customer details you want to collect.

const applePayFields = {
  requestBillingAddress: true,  // ask for billing address
  requestPayerEmail: true,      // ask for email
  requestPayerPhone: true,      // ask for phone
  requestShipping: false,       // ask for shipping info
  requestPayerName: true,       // ask for full name
};
6Initialize Apple Pay

Call the SDK function with all configurations.

📌 merchantId → Provided by iPOSpays

📌 merchantIdentifier → Created in Apple Developer portal

initializeApplePay(
  transactionInfo,
  buttonStyles,
  "YOUR_MERCHANT_ID",              // Replace with your merchant ID
  applePayFields,
  "YOUR_APPLE_MERCHANT_IDENTIFIER" // From Apple Developer account
);
7Capture Apple Pay Payment Data

When a customer approves the Apple Pay sheet, the SDK will return a paymentData object. Capture it using:

function getApplePaymentInfo(paymentData) {
  console.log("Apple Pay Payment Data:", paymentData);

  // Forward to your transaction handler
  iposTransactApi(paymentData);
}
8Send Data to Your Backend

The function iposTransactApi() should send the paymentData token to your server, where you finalize the payment.

⚠️ You will customize iposTransactApi() in your integration to send the Apple Pay token to your server.

function iposTransactApi(paymentData) {
  fetch("/your-backend-endpoint", {
    method: "POST",
    headers: {
      "Content-Type": "application/json"
    },
    body: JSON.stringify({ applePayToken: paymentData })
  })
    .then(res => res.json())
    .then(result => {
      if (result.success) {
        alert("✅ Payment Successful");
      } else {
        alert("❌ Payment Failed: " + result.message);
      }
    })
    .catch(err => console.error("Error:", err));
}
9Full Example Code

Here's everything combined:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Apple Pay Checkout</title>
  <script src="https://ftd.denovosystem.tech/ftd/v1/apple-pay.js" id="applepayftd"></script>
</head>
<body>
  <!-- Apple Pay Button -->
  <div id="ipospays-apple-pay-button"></div>

  <script>
    const transactionInfo = {
      countryCode: "US",
      currencyCode: "USD",
      totalPriceStatus: "FINAL",
      totalPrice: "49.99",
    };

    const buttonStyles = {
      buttonColor: "black",
      buttonType: "buy",
      buttonRadius: "8px",
      buttonLocale: "en-US",
      buttonHeight: "50px",
      buttonWidth: "100%",
    };

    const applePayFields = {
      requestBillingAddress: true,
      requestPayerEmail: true,
      requestPayerPhone: true,
      requestShipping: false,
      requestPayerName: true,
    };

    // Initialize Apple Pay
    initializeApplePay(
      transactionInfo,
      buttonStyles,
      "YOUR_MERCHANT_ID",
      applePayFields,
      "YOUR_APPLE_MERCHANT_IDENTIFIER"
    );

    // Capture Payment Data
    function getApplePaymentInfo(paymentData) {
      console.log("Apple Pay Data:", paymentData);
      iposTransactApi(paymentData);
    }

    // Send to Backend
    function iposTransactApi(paymentData) {
      fetch("/your-backend-endpoint", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ applePayToken: paymentData })
      })
        .then(res => res.json())
        .then(result => console.log("Payment Result:", result))
        .catch(err => console.error("Error:", err));
    }
  </script>
</body>
</html>

Next Steps

  • Replace YOUR_MERCHANT_ID and YOUR_APPLE_MERCHANT_IDENTIFIER with real values.
  • Implement the backend API (/your-backend-endpoint) to receive the Apple Pay token and complete payment with iPOSpays.
  • Test in Sandbox/Test Mode.
  • After Apple domain verification, go live.

ACH

Use the following steps to integrate FreedomToDesign with ACH payments using the iposTransact API.

This JavaScript file is used to render mandatory fields based on the TPN configured with ACH service. Based on the required ACH tags, you can build logic to present the appropriate fields to the user. Once filled, this data is sent using the iposTransact API via the achData tag.

Prerequisites

Before integrating, ensure you have:

  • An HTML page where you want to display the ACH payment form
  • Your ecomm auth token (also referred to as security_key)
  • Basic knowledge of HTML and JavaScript
1Add the Script to Your Page

Include the FreedomToDesign JavaScript library on your page. This script renders the ACH form and provides metadata via callback.

Place the following <script> tag before the closing </body> tag of your HTML.

<script
  defer
  src="https://payment.ipospays.tech/ftd/v1/ipospays-ftd-ach.js"
  id="ftdach"
  security_key="auth_token">
</script>

Replace auth_token with your actual ecomm auth token.

2Insert Form Field Containers

Add the following <div> elements to your HTML page. These act as placeholders for dynamically rendered form fields.

The IDENTITY field will trigger conditional visibility for SSN and DOB fields. This logic is handled by the Integrators.

index.html
<form id="achPaymentForm">
  <h3>ACH Payment Details</h3>

  <div id="FIRST_NAME"></div>
  <div id="LAST_NAME"></div>
  <div id="PHONE_NUMBER"></div>
  <div id="EMAIL"></div>
  <div id="ADDRESS1"></div>
  <div id="ADDRESS2"></div>
  <div id="CITY"></div>
  <div id="STATE"></div>
  <div id="ZIP"></div>
  <div id="DL_NUMBER"></div>
  <div id="DL_STATE"></div>

  <hr>

  <h4>Account Information</h4>
  <div id="ACCOUNT_NUMBER"></div>
  <div id="ROUTING_NUMBER"></div>
  <div id="ACCOUNT_TYPE"></div>

  <hr>

  <h4>Identity Verification</h4>
  <div id="IDENTITY"></div>
  <div id="SSN"></div>
  <div id="DOB"></div>

  <hr>

  <h4>Custom Tags</h4>
  <div id="CUSTOM_TAG1"></div>
  <div id="CUSTOM_TAG2"></div>
  <div id="CUSTOM_TAG3"></div>

  <button type="submit" id="submitAchButton">Process ACH Payment</button>
</form>
3Initialize Form and Handle Metadata Callback

You must define window.getAchPaymentInfo before initializing the form to receive terminal-level data (terminalId, entryClass, usersId) required for processing the transaction.

<script>
  const SECURITY_KEY = "YOUR_ECOMM_AUTH_TOKEN_HERE";
  let achTransactionMetadata = {};

  window.getAchPaymentInfo = function (data) {
    console.log("Received ACH Payment Info:", data);
    achTransactionMetadata = data;
  };

  async function initializePage() {
    if (typeof initializeAchForm === "function") {
      try {
        let isAch = await initializeAchForm({ security_key: SECURITY_KEY });

        if (isAch) {
          window.getAchPaymentInfo = (achPaymentInfoData) => {
            console.log("Received payment info:", achPaymentInfoData);
            achTransactionMetadata = achPaymentInfoData;
          };

          window.getallFieldsData = (allFields) => {
            console.log("Received getallFields info:", allFields);
          };
        }

        console.log("ACH form initialized.");
      } catch (error) {
        console.error("Initialization failed:", error);
      }
    } else {
      console.error("initializeAchForm not available.");
    }
  }

  document
    .getElementById("submitAchButton")
    .addEventListener("click", async (e) => {
      e.preventDefault();

      if (
        !achTransactionMetadata.terminalId ||
        !achTransactionMetadata.entryClass ||
        !achTransactionMetadata.usersId ||
        !achTransactionMetadata.identity
      ) {
        alert("Form not fully loaded. Please wait.");
        return;
      }

      // Example placeholder: Get customer data (implementation depends on FreedomToDesign library)
      // const customerAchData = getCustomerAchDataFromForm();

      alert("Form submitted! Check console for received metadata.");
    });
</script>
4Submit Data to iposTransact API from Backend

Once you have customer-entered data and metadata from the callback, submit the transaction using your backend service.

Backend API Call Example (Node.js)
async function processAchTransactionOnBackend(customerAchData, achTransactionMetadata) {
  {
    "merchantAuthentication": {
      "merchantId": "567024937072",// TPN provided by Dejavoo
      "transactionReferenceId": "7639491755250417905532" //Unique TransactionRefId for each Transaction
    },
    "transactionRequest": {
      "transactionType": 10,//ACH - Sale transaction 
      "amount": "1000",// Example: 1000 = $10.00 (amount is in cents, divided by 100)
      "sourceType": "ACH-FTD"
    },
    "preferences": {
      "customerName": "Customer_Name", // Customer Name
      "customerEmail": "Customer_Email",// Customer Email Id
      "customerMobile": "+1234567891", // Customer Mobile Number
      "requestAchToken": true // true- Then it will share the achToken in Response if transaction is Approved. False - We will not share the achToken
    },
    "achData": {
      firstName: customerAchData.FIRST_NAME || "", 
      lastName: customerAchData.LAST_NAME || "", 
      addressOne: customerAchData.ADDRESS1 || "",
      addressTwo: customerAchData.ADDRESS2 || "", 
      state: customerAchData.STATE || "", 
      dlNumber: customerAchData.DL_NUMBER || "", 
      dlState: customerAchData.DL_STATE || "", 
      accountNumber: customerAchData.ACCOUNT_NUMBER || "", 
      accountType: customerAchData.ACCOUNT_TYPE || "", 
      routingNumber: customerAchData.ROUTING_NUMBER || "", 
      description: customerAchData.DESCRIPTION || "",
      ssn: customerAchData.SSN || "", 
      dobYear: customerAchData.DOB || "", 
      city: customerAchData.CITY || "", 
      zipCode: customerAchData.ZIP || "", 
      identity: achTransactionMetadata.identity, 
      terminalId: achTransactionMetadata.terminalId,
      entryClass: achTransactionMetadata.entryClass, 
      usersId: achTransactionMetadata.usersId, 
      tipAmount: "0",
      "tagLabel": "achTransactionMetadata.tagLabel",
      "tagValue": `${customerAchData.CUSTOM_TAG1},${customerAchData.CUSTOM_TAG2},${ customerAchData.CUSTOM_TAG3}`,
      "custom1": "customerAchData.CUSTOM_TAG1 || """,
      "custom2": "customerAchData.CUSTOM_TAG2 || """,
      "custom3": "customerAchData.CUSTOM_TAG3 || """,
    }
  };

  const response = await fetch("YOUR_IPOS_TRANSACT_API_ENDPOINT", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(payload),
  });

  const result = await response.json();
  if (response.ok) {
    console.log("ACH Transaction successful:", result);
  } else {
    console.error("ACH Transaction failed:", result);
  }
}

Errors

For a complete list of error codes and their explanations, please visit our Error Codes Reference Page.

Last updated on July 27, 2026