Skip to main content
Add a TON Pay button to a plain HTML/JavaScript page using the embed script or TON Pay client.

Installation

1

Choose an installation method

Choose one of the installation methods:
  1. npm
    npm install @ton-pay/ui @tonconnect/ui
    
  2. CDN: no installation needed
    <!-- Use the unpkg CDN directly in HTML -->
    <script src="https://unpkg.com/@ton-pay/[email protected]/dist/ton-pay-embed.js"></script>
    
  3. Local copy After npm install, copy node_modules/@ton-pay/ui/dist/ton-pay-embed.js to a public assets folder. For example, the site’s public/ directory. Then include it with a <script src="..."> tag in HTML.
2

Create a TON Connect manifest

Create a tonconnect-manifest.json file and host it on a public HTTPS URL.
{
  "url": "<APP_URL>",
  "name": "<APP_NAME>",
  "iconUrl": "<APP_ICON_URL>"
}
Placeholders:
  • <APP_URL> – public HTTPS URL of the app.
  • <APP_NAME> – display name shown in the wallet.
  • <APP_ICON_URL> – public HTTPS URL of the app icon.

Option 1: embed script

Placeholders:
  • <CONTAINER_ID> – HTML element ID where the button is mounted.
  • <CALLBACK_NAME> – global function name invoked by the embed script.
  • <RECIPIENT_ADDR> – recipient wallet address.
1

Add the container

<div id="<CONTAINER_ID>"></div>
2

Add the embed script

<script src="https://unpkg.com/@ton-pay/[email protected]/dist/ton-pay-embed.js?preset=gradient&variant=long&borderRadius=8&containerId=<CONTAINER_ID>&callback=<CALLBACK_NAME>"></script>
3

Add the import map

<script type="importmap">
  {
      "imports": {
      "@tonconnect/ui": "https://esm.sh/@tonconnect/[email protected]"
    }
  }
</script>
4

Create the payment handler

<script type="module">
    import { createTonPay } from "https://unpkg.com/@ton-pay/[email protected]/dist/ton-pay-vanilla.mjs";

    // Initialize TonPay client
    const tonPay = createTonPay({
      manifestUrl: "/tonconnect-manifest.json"
    });

    // Define payment handler
    window["<CALLBACK_NAME>"] = async () => {
      try {
        const result = await tonPay.pay(async (senderAddr) => {
        // Build the payment message
          const message = {
            address: "<RECIPIENT_ADDR>",
            amount: "1000000", // 0.001 TON in nanotons
            payload: "dGVzdA==", // optional base64 payload
          };
          return { message };
        });

        console.log("Payment successful:", result.txResult);
        alert("Payment sent!");
      } catch (error) {
        console.error("Payment failed:", error);
        alert("Payment failed: " + error.message);
  }
};
</script>
The callback parameter in the embed script must match the global function name in the handler.

Option 2: use TON Pay client

Use createTonPay for custom UI and payment flow control.
1

Set up the HTML

<!DOCTYPE html>
<html>
<head>
  <title>My TON Payment App</title>
  <script type="importmap">
    {
      "imports": {
      "@tonconnect/ui": "https://esm.sh/@tonconnect/[email protected]"
    }
    }
  </script>
</head>
<body>
  <button id="pay-btn">Pay with TON</button>
  <div id="status"></div>
</body>
</html>
2

Import the TON Pay client and create an instance

<script type="module">
  import { createTonPay } from "https://unpkg.com/@ton-pay/[email protected]/dist/ton-pay-vanilla.mjs";

  const tonPay = createTonPay({
    manifestUrl: "/tonconnect-manifest.json",
    connectTimeoutMs: 300000 // 5 minutes (optional)
});
</script>
3

Implement the payment logic

<script type="module">
  const payButton = document.getElementById("pay-btn");
  const statusDiv = document.getElementById("status");

  payButton.addEventListener("click", async () => {
    payButton.disabled = true;
    payButton.textContent = "Processing...";

    try {
      const result = await tonPay.pay(async (senderAddr) => {
        statusDiv.textContent = `Sending from ${senderAddr}...`;

        // Build payment message
        const message = {
          address: "<RECIPIENT_ADDR>",
          amount: "1000000",
        };

        return { message };
      });

      statusDiv.textContent = "Payment successful!";
      console.log("Transaction:", result.txResult);
    } catch (error) {
      statusDiv.textContent = "Payment failed: " + error.message;
      console.error(error);
    } finally {
      payButton.disabled = false;
      payButton.textContent = "Pay with TON";
    }
  });
</script>
createTonPay opens TON Connect modal when pay() is called and no wallet is connected.

Create messages with createTonPayTransfer

Use createTonPayTransfer to build a canonical payment message with tracking identifiers. Combine the snippets in this section into one HTML page.
1

Add the API package script

<script type="module">
  import { createTonPayTransfer } from "https://unpkg.com/@ton-pay/[email protected]/dist/index.mjs";
  import { createTonPay } from "https://unpkg.com/@ton-pay/[email protected]/dist/ton-pay-vanilla.mjs";
</script>
2

Use the API in the payment handler

<script type="module">
  const tonPay = createTonPay({
    manifestUrl: "/tonconnect-manifest.json"
  });

  window["<CALLBACK_NAME>"] = async () => {
    try {
      const result = await tonPay.pay(async (senderAddr) => {
        // Create payment with tracking
        const { message, reference, bodyBase64Hash } =
          await createTonPayTransfer(
            {
              amount: 3.5,
              asset: "TON",
              recipientAddr: "<RECIPIENT_ADDR>",
              senderAddr,
              commentToSender: "Order #12345",
            },
            { chain: "mainnet" }
          );

        // Store tracking identifiers
        console.log("Reference:", reference);
        console.log("Hash:", bodyBase64Hash);

        return { message, reference, bodyBase64Hash };
      });

      alert("Payment sent! Reference: " + result.reference);
    } catch (error) {
      alert("Payment failed: " + error.message);
    }
  };
</script>
Store reference and bodyBase64Hash to track payment status via the webhooks guide.

Embed script parameters

ParameterTypeDefaultDescription
containerIdstring"ton-pay-btn"Target element ID where the button renders.
preset"default" | "gradient"-Built-in theme preset.
bgColorstring"#0098EA"Background color in hex or CSS gradient. URL-encode the value.
textColorstring"#FFFFFF"Text and icon color.
variant"long" | "short""long"Button text variant.
textstring-Custom button text. Overrides variant.
loadingTextstring"Processing..."Text shown during loading.
borderRadiusnumber8Border radius in pixels.
fontFamilystring"inherit"CSS font-family value.
widthnumber300Button width in pixels.
heightnumber44Button height in pixels.
showMenubooleantrueShow dropdown menu with wallet actions.
callbackstring-Global function name called on click.

Examples

<script src="https://unpkg.com/@ton-pay/[email protected]/dist/ton-pay-embed.js?preset=default&variant=long&borderRadius=8&containerId=btn-1&callback=handlePayment"></script>
URL-encode special characters in parameters. For example, # becomes %23 in color values.

TonPayEmbed API

The embed script exposes a global TonPayEmbed object for programmatic control.

TonPayEmbed.mount(config)

Update button configuration dynamically.
TonPayEmbed.mount({
  preset: "gradient",
  variant: "short",
  borderRadius: 12,
  width: 350
});

TonPayEmbed.setCallback(functionName)

Change the callback function.
TonPayEmbed.setCallback("newPaymentHandler");

TonPayEmbed.setAddress(address)

Update the displayed wallet address in the menu.
TonPayEmbed.setAddress("<RECIPIENT_ADDR>");

TonPayEmbed.click()

Trigger a button click programmatically.
TonPayEmbed.click();

Example: dynamic configuration

<div id="<CONTAINER_ID>"></div>
<button onclick="changeTheme()">Change Theme</button>

<script src="https://unpkg.com/@ton-pay/[email protected]/dist/ton-pay-embed.js?containerId=<CONTAINER_ID>&callback=<CALLBACK_NAME>"></script>

<script>
  function changeTheme() {
    TonPayEmbed.mount({
      preset: "gradient",
      variant: "short",
      borderRadius: 99
    });
  }
</script>

TonPay client API

createTonPay returns a client for wallet connection and payments.

Properties

  • address: string | null Current wallet address.
    const tonPay = createTonPay({ manifestUrl: "/tonconnect-manifest.json" });
    console.log(tonPay.address); // null or wallet address
    

Methods

  • waitForWalletConnection(): Promise<string> Wait for a wallet connection and open the modal if needed.
    try {
      const address = await tonPay.waitForWalletConnection();
      console.log("Connected:", address);
    } catch (error) {
      console.error("Connection failed:", error);
    }
    
  • pay(getMessage): Promise<PayResult> Execute a payment transaction.
    const result = await tonPay.pay(async (senderAddr) => {
      const message = {
        address: "<RECIPIENT_ADDR>",
        amount: "1000000"
      };
      return { message };
    });
    
    console.log(result.txResult);
    
  • disconnect(): Promise<void> Disconnect the current wallet.
    await tonPay.disconnect();
    

Framework integration

WordPress

<!-- Add to the theme footer or a custom HTML block -->
<div id="<CONTAINER_ID>"></div>
<script type="importmap">
{
  "imports": {
    "@tonconnect/ui": "https://esm.sh/@tonconnect/[email protected]"
  }
}
</script>
<script type="module">
  import { createTonPay } from "https://unpkg.com/@ton-pay/[email protected]/dist/ton-pay-vanilla.mjs";
  const tonPay = createTonPay({ manifestUrl: "/tonconnect-manifest.json" });
  window["<CALLBACK_NAME>"] = async () => { /* payment handler */ };
</script>
<script src="https://unpkg.com/@ton-pay/[email protected]/dist/ton-pay-embed.js?containerId=<CONTAINER_ID>&callback=<CALLBACK_NAME>"></script>

Plain HTML/CSS/JS

Use the complete example of the embed script in a single HTML file.

Build tools: Webpack and Vite

import { createTonPay } from "@ton-pay/ui/vanilla";

const tonPay = createTonPay({
  manifestUrl: "/tonconnect-manifest.json"
});

// Use tonPay.pay() in event handlers

Best practices

  • Wrap payment calls in try-catch blocks and display clear error messages.
  • Update the UI during payment processing to prevent repeated clicks.
  • Check amounts, addresses, and input before calling the payment function.
  • Use HTTPS in production. TON Connect requires HTTPS for the manifest URL and callbacks.
  • Save reference and bodyBase64Hash from createTonPayTransfer to track payments via webhooks.
  • Test with testnet first and handle error scenarios before going live.

Troubleshooting

  1. Verify that containerId matches the target div ID
  2. Check the browser console for errors
  3. Ensure the script loads after the container div
  4. Verify that the script URL is correct and accessible
  1. Ensure the callback function is defined on the window object
  2. Verify that the function name matches the callback parameter exactly
  3. Define the callback before the embed script runs
  1. Add the import map before any module scripts
  2. Verify that the @tonconnect/ui version is compatible
  3. Check that the import map syntax is valid
  1. Serve the manifest from the same domain or enable CORS
  2. Use HTTPS in production
  3. Verify that CDN resources are accessible