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

<AgentInstructions>

## Submitting Feedback

If you encounter incorrect, outdated, or confusing documentation on this page, submit feedback:

POST https://docs.ton.org/feedback

```json
{
  "path": "/ecosystem/ton-pay/ui-integration/button-js",
  "feedback": "Description of the issue"
}
```

Only submit feedback when you have something specific and actionable to report.

</AgentInstructions>

# How to add a TON Pay button using JS

export const Image = ({src, darkSrc, alt = '', darkAlt, href, target, height = 342, width = 608, noZoom = false, center = false}) => {
  const isSVG = src.match(/\.svg(?:[#?].*?)?$/i) !== null;
  const shouldInvert = isSVG && !darkSrc;
  const shouldCreateLink = href !== undefined;
  const minPx = 9;
  const maxPx = 608;
  const expectedPx = `a number or a string with a number that is greater than ${minPx - 1} and less than or equal to ${maxPx}`;
  const createInvalidPropCallout = (title, received, expected) => {
    return <Danger>
        <span className="font-bold">
          Invalid <code>{title.toString()}</code> passed!
        </span>
        <br />
        <span className="font-bold">Received: </span>
        {received.toString()}
        <br />
        <span className="font-bold">Expected: </span>
        {expected.toString()}
        {}
      </Danger>;
  };
  const checkValidDimensionValue = value => {
    switch (typeof value) {
      case "string":
      case "number":
        const num = Number(value);
        return Number.isSafeInteger(num) && num >= minPx && num <= maxPx;
      default:
        return false;
    }
  };
  let callouts = [];
  if (height && !checkValidDimensionValue(height)) {
    callouts.push(createInvalidPropCallout("height", height, expectedPx));
  }
  if (width && !checkValidDimensionValue(width)) {
    callouts.push(createInvalidPropCallout("width", width, expectedPx));
  }
  if (callouts.length !== 0) {
    return callouts;
  }
  const heightPx = Number(height);
  const widthPx = Number(width);
  const shouldCenter = center === "true" || center === true ? true : false;
  const shouldNotZoom = noZoom === "true" || noZoom === true ? true : false;
  const images = <>
      <img className="block dark:hidden" src={src} alt={alt} {...height && ({
    height: heightPx
  })} {...width && ({
    width: widthPx
  })} {...(shouldCreateLink || shouldInvert || shouldNotZoom) && ({
    noZoom: "true"
  })} />
      <img className={`hidden dark:block ${shouldInvert ? "invert" : ""}`} src={darkSrc ?? src} alt={darkAlt ?? alt} {...height && ({
    height: heightPx
  })} {...width && ({
    width: widthPx
  })} {...(shouldCreateLink || shouldInvert || shouldNotZoom) && ({
    noZoom: "true"
  })} />
    </>;
  if (shouldCreateLink) {
    if (shouldCenter) {
      return <div style={{
        display: "flex",
        justifyContent: "center"
      }}>
          <a href={href} target={target ?? "_self"}>
            {images}
          </a>
        </div>;
    }
    return <a href={href} target={target ?? "_self"}>
        {images}
      </a>;
  }
  if (shouldCenter) {
    return <div style={{
      display: "flex",
      justifyContent: "center"
    }}>{images}</div>;
  }
  return images;
};

export const Aside = ({type = "note", title = "", icon = "", iconType = "regular", children}) => {
  const asideVariants = ["note", "tip", "caution", "danger"];
  const asideComponents = {
    note: {
      outerStyle: "border-sky-500/20 bg-sky-50/50 dark:border-sky-500/30 dark:bg-sky-500/10",
      innerStyle: "text-sky-900 dark:text-sky-200",
      calloutType: "note",
      icon: <svg width="14" height="14" viewBox="0 0 14 14" fill="currentColor" xmlns="http://www.w3.org/2000/svg" className="w-4 h-4 text-sky-500" aria-label="Note">
          <path fill-rule="evenodd" clip-rule="evenodd" d="M7 1.3C10.14 1.3 12.7 3.86 12.7 7C12.7 10.14 10.14 12.7 7 12.7C5.48908 12.6974 4.0408 12.096 2.97241 11.0276C1.90403 9.9592 1.30264 8.51092 1.3 7C1.3 3.86 3.86 1.3 7 1.3ZM7 0C3.14 0 0 3.14 0 7C0 10.86 3.14 14 7 14C10.86 14 14 10.86 14 7C14 3.14 10.86 0 7 0ZM8 3H6V8H8V3ZM8 9H6V11H8V9Z"></path>
        </svg>
    },
    tip: {
      outerStyle: "border-emerald-500/20 bg-emerald-50/50 dark:border-emerald-500/30 dark:bg-emerald-500/10",
      innerStyle: "text-emerald-900 dark:text-emerald-200",
      calloutType: "tip",
      icon: <svg width="11" height="14" viewBox="0 0 11 14" fill="currentColor" xmlns="http://www.w3.org/2000/svg" className="text-emerald-600 dark:text-emerald-400/80 w-3.5 h-auto" aria-label="Tip">
          <path d="M3.12794 12.4232C3.12794 12.5954 3.1776 12.7634 3.27244 12.907L3.74114 13.6095C3.88471 13.8248 4.21067 14 4.46964 14H6.15606C6.41415 14 6.74017 13.825 6.88373 13.6095L7.3508 12.9073C7.43114 12.7859 7.49705 12.569 7.49705 12.4232L7.50055 11.3513H3.12521L3.12794 12.4232ZM5.31288 0C2.52414 0.00875889 0.5 2.26889 0.5 4.78826C0.5 6.00188 0.949566 7.10829 1.69119 7.95492C2.14321 8.47011 2.84901 9.54727 3.11919 10.4557C3.12005 10.4625 3.12175 10.4698 3.12261 10.4771H7.50342C7.50427 10.4698 7.50598 10.463 7.50684 10.4557C7.77688 9.54727 8.48281 8.47011 8.93484 7.95492C9.67728 7.13181 10.1258 6.02703 10.1258 4.78826C10.1258 2.15486 7.9709 0.000106649 5.31288 0ZM7.94902 7.11267C7.52078 7.60079 6.99082 8.37878 6.6077 9.18794H4.02051C3.63739 8.37878 3.10743 7.60079 2.67947 7.11294C2.11997 6.47551 1.8126 5.63599 1.8126 4.78826C1.8126 3.09829 3.12794 1.31944 5.28827 1.3126C7.2435 1.3126 8.81315 2.88226 8.81315 4.78826C8.81315 5.63599 8.50688 6.47551 7.94902 7.11267ZM4.87534 2.18767C3.66939 2.18767 2.68767 3.16939 2.68767 4.37534C2.68767 4.61719 2.88336 4.81288 3.12521 4.81288C3.36705 4.81288 3.56274 4.61599 3.56274 4.37534C3.56274 3.6515 4.1515 3.06274 4.87534 3.06274C5.11719 3.06274 5.31288 2.86727 5.31288 2.62548C5.31288 2.38369 5.11599 2.18767 4.87534 2.18767Z"></path>
        </svg>
    },
    caution: {
      outerStyle: "border-amber-500/20 bg-amber-50/50 dark:border-amber-500/30 dark:bg-amber-500/10",
      innerStyle: "text-amber-900 dark:text-amber-200",
      calloutType: "warning",
      icon: <svg className="flex-none w-5 h-5 text-amber-400 dark:text-amber-300/80" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" aria-label="Warning">
          <path stroke-linecap="round" stroke-linejoin="round" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"></path>
        </svg>
    },
    danger: {
      outerStyle: "border-red-500/20 bg-red-50/50 dark:border-red-500/30 dark:bg-red-500/10",
      innerStyle: "text-red-900 dark:text-red-200",
      calloutType: "danger",
      icon: <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="currentColor" className="text-red-600 dark:text-red-400/80 w-4 h-4" aria-label="Danger">
          <path d="M17.1 292c-12.9-22.3-12.9-49.7 0-72L105.4 67.1c12.9-22.3 36.6-36 62.4-36l176.6 0c25.7 0 49.5 13.7 62.4 36L494.9 220c12.9 22.3 12.9 49.7 0 72L406.6 444.9c-12.9 22.3-36.6 36-62.4 36l-176.6 0c-25.7 0-49.5-13.7-62.4-36L17.1 292zm41.6-48c-4.3 7.4-4.3 16.6 0 24l88.3 152.9c4.3 7.4 12.2 12 20.8 12l176.6 0c8.6 0 16.5-4.6 20.8-12L453.4 268c4.3-7.4 4.3-16.6 0-24L365.1 91.1c-4.3-7.4-12.2-12-20.8-12l-176.6 0c-8.6 0-16.5 4.6-20.8 12L58.6 244zM256 128c13.3 0 24 10.7 24 24l0 112c0 13.3-10.7 24-24 24s-24-10.7-24-24l0-112c0-13.3 10.7-24 24-24zM224 352a32 32 0 1 1 64 0 32 32 0 1 1 -64 0z"></path>
        </svg>
    }
  };
  let variant = type;
  let gotInvalidVariant = false;
  if (!asideVariants.includes(type)) {
    gotInvalidVariant = true;
    variant = "danger";
  }
  const iconVariants = ["regular", "solid", "light", "thin", "sharp-solid", "duotone", "brands"];
  if (!iconVariants.includes(iconType)) {
    iconType = "regular";
  }
  return <>
      <div className={`callout my-4 px-5 py-4 overflow-hidden rounded-2xl flex gap-3 border ${asideComponents[variant].outerStyle}`} data-callout-type={asideComponents[variant].calloutType}>
        <div className="mt-0.5 w-4" data-component-part="callout-icon">
          {}
          {icon === "" ? asideComponents[variant].icon : <Icon icon={icon} iconType={iconType} size={14} />}
        </div>
        <div className={`text-sm prose min-w-0 w-full ${asideComponents[variant].innerStyle}`} data-component-part="callout-content">
          {gotInvalidVariant ? <p>
              <span className="font-bold">
                Invalid <code>type</code> passed!
              </span>
              <br />
              <span className="font-bold">Received: </span>
              {type}
              <br />
              <span className="font-bold">Expected one of: </span>
              {asideVariants.join(", ")}
            </p> : <>
              {title && <p className="font-bold">{title}</p>}
              {children}
            </>}
        </div>
      </div>
    </>;
};

Add a TON Pay button to a plain HTML/JavaScript page using the embed script or TON Pay client. The default button appearance is shown below.

<div style={{ display: "flex", justifyContent: "center" }}>
  <Image src="/resources/images/ton-pay/button.png" alt="TON Pay button" width={300} noZoom={true} />
</div>

## Installation

<Steps>
  <Step title="Choose an installation method">
    Choose one of the installation methods:

    1. npm

       ```bash theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
       npm install @ton-pay/ui @tonconnect/ui
       ```

    2. CDN: no installation needed

       ```html theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
       <!-- Use the unpkg CDN directly in HTML -->
       <script src="https://unpkg.com/@ton-pay/ui@0.1.1/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.
  </Step>

  <Step title="Create a TON Connect manifest">
    Create a [`tonconnect-manifest.json` file](/ecosystem/ton-connect/manifest) and host it on a public HTTPS URL.

    ```json theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
    {
      "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.
  </Step>
</Steps>

## 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.

<Steps>
  <Step title="Add the container">
    ```html theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
    <div id="<CONTAINER_ID>"></div>
    ```
  </Step>

  <Step title="Add the embed script">
    ```html theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
    <script src="https://unpkg.com/@ton-pay/ui@0.1.1/dist/ton-pay-embed.js?preset=gradient&variant=long&borderRadius=8&containerId=<CONTAINER_ID>&callback=<CALLBACK_NAME>"></script>
    ```
  </Step>

  <Step title="Add the import map">
    ```html theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
    <script type="importmap">
      {
          "imports": {
          "@tonconnect/ui": "https://esm.sh/@tonconnect/ui@2.0.9"
        }
      }
    </script>
    ```
  </Step>

  <Step title="Create the payment handler">
    ```html theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
    <script type="module">
        import { createTonPay } from "https://unpkg.com/@ton-pay/ui@0.1.1/dist/ton-pay-vanilla.mjs";

        // Initialize TonPay client
        const tonPay = createTonPay({
          manifestUrl: "https://<APP_URL>/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>
    ```
  </Step>
</Steps>

<Aside type="note">
  The `callback` parameter in the embed script must match the global function name in the handler.
</Aside>

## Option 2: use TON Pay client

Use `createTonPay` for custom UI and payment flow control.

<Steps>
  <Step title="Set up the HTML">
    ```html theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
    <!DOCTYPE html>
    <html>
    <head>
      <title>My TON Payment App</title>
      <script type="importmap">
        {
          "imports": {
          "@tonconnect/ui": "https://esm.sh/@tonconnect/ui@2.0.9"
        }
        }
      </script>
    </head>
    <body>
      <button id="pay-btn">Pay with TON</button>
      <div id="status"></div>
    </body>
    </html>
    ```
  </Step>

  <Step title="Import the TON Pay client and create an instance">
    ```html theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
    <script type="module">
      import { createTonPay } from "https://unpkg.com/@ton-pay/ui@0.1.1/dist/ton-pay-vanilla.mjs";

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

  <Step title="Implement the payment logic">
    ```html theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
    <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>
    ```

    <Aside type="note">
      `createTonPay` opens TON Connect modal when `pay()` is called and no wallet is connected.
    </Aside>
  </Step>
</Steps>

## 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.

<Steps>
  <Step title="Add the API package script">
    ```html theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
    <script type="module">
      import { createTonPayTransfer } from "https://unpkg.com/@ton-pay/api@0.2.1/dist/index.mjs";
      import { createTonPay } from "https://unpkg.com/@ton-pay/ui@0.1.1/dist/ton-pay-vanilla.mjs";
    </script>
    ```
  </Step>

  <Step title="Use the API in the payment handler">
    ```html theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
    <script type="module">
      const tonPay = createTonPay({
        manifestUrl: "https://<APP_URL>/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>
    ```
  </Step>
</Steps>

<Aside type="note">
  Store `reference` and `bodyBase64Hash` to track payment status via the [webhooks guide](/ecosystem/ton-pay/webhooks).
</Aside>

## Embed script parameters

| Parameter      | Type                        | Default           | Description                                                    |
| -------------- | --------------------------- | ----------------- | -------------------------------------------------------------- |
| `containerId`  | string                      | `"ton-pay-btn"`   | Target element ID where the button renders.                    |
| `preset`       | `"default"` \| `"gradient"` | -                 | Built-in theme preset.                                         |
| `bgColor`      | string                      | `"#0098EA"`       | Background color in hex or CSS gradient. URL-encode the value. |
| `textColor`    | string                      | `"#FFFFFF"`       | Text and icon color.                                           |
| `variant`      | `"long"` \| `"short"`       | `"long"`          | Button text variant.                                           |
| `text`         | string                      | -                 | Custom button text. Overrides `variant`.                       |
| `loadingText`  | string                      | `"Processing..."` | Text shown during loading.                                     |
| `borderRadius` | number                      | `8`               | Border radius in pixels.                                       |
| `fontFamily`   | string                      | `"inherit"`       | CSS font-family value.                                         |
| `width`        | number                      | `300`             | Button width in pixels.                                        |
| `height`       | number                      | `44`              | Button height in pixels.                                       |
| `showMenu`     | boolean                     | `true`            | Show dropdown menu with wallet actions.                        |
| `callback`     | string                      | -                 | Global function name called on click.                          |

### Examples

<CodeGroup>
  ```html Default blue button theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
  <script src="https://unpkg.com/@ton-pay/ui@0.1.1/dist/ton-pay-embed.js?preset=default&variant=long&borderRadius=8&containerId=btn-1&callback=handlePayment"></script>
  ```

  ```html Gradient button theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
  <script src="https://unpkg.com/@ton-pay/ui@0.1.1/dist/ton-pay-embed.js?preset=gradient&variant=short&borderRadius=12&containerId=btn-2&callback=handlePayment"></script>
  ```

  ```html Custom colors theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
  <script src="https://unpkg.com/@ton-pay/ui@0.1.1/dist/ton-pay-embed.js?bgColor=%23000000&textColor=%23FFFFFF&borderRadius=99&containerId=btn-3&callback=handlePayment"></script>
  ```

  ```html Custom size theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
  <script src="https://unpkg.com/@ton-pay/ui@0.1.1/dist/ton-pay-embed.js?preset=gradient&width=400&height=56&containerId=btn-4&callback=handlePayment"></script>
  ```
</CodeGroup>

<Aside type="caution">
  URL-encode special characters in parameters. For example, `#` becomes `%23` in color values.
</Aside>

## TonPayEmbed API

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

### `TonPayEmbed.mount(config)`

Update button configuration dynamically.

```js theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
TonPayEmbed.mount({
  preset: "gradient",
  variant: "short",
  borderRadius: 12,
  width: 350
});
```

### `TonPayEmbed.setCallback(functionName)`

Change the callback function.

```js theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
TonPayEmbed.setCallback("newPaymentHandler");
```

### `TonPayEmbed.setAddress(address)`

Update the displayed wallet address in the menu.

```js theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
TonPayEmbed.setAddress("<RECIPIENT_ADDR>");
```

### `TonPayEmbed.click()`

Trigger a button click programmatically.

```js theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
TonPayEmbed.click();
```

### Example: dynamic configuration

```html theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
<div id="<CONTAINER_ID>"></div>
<button onclick="changeTheme()">Change Theme</button>

<script src="https://unpkg.com/@ton-pay/ui@0.1.1/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.

  ```js theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
  const tonPay = createTonPay({ manifestUrl: "https://<APP_URL>/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.

  ```js theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
  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.

  ```js theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
  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.

  ```js theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
  await tonPay.disconnect();
  ```

## Framework integration

### WordPress

```html theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
<!-- 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/ui@2.0.9"
  }
}
</script>
<script type="module">
  import { createTonPay } from "https://unpkg.com/@ton-pay/ui@0.1.1/dist/ton-pay-vanilla.mjs";
  const tonPay = createTonPay({ manifestUrl: "https://<APP_URL>/tonconnect-manifest.json" });
  window["<CALLBACK_NAME>"] = async () => { /* payment handler */ };
</script>
<script src="https://unpkg.com/@ton-pay/ui@0.1.1/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

```js theme={"theme":{"light":"github-light-default","dark":"dark-plus"},"languages":{"custom":["/resources/grammars/tolk.tmLanguage.json","/resources/grammars/tlb.tmLanguage.json","/resources/grammars/fift.tmLanguage.json","/resources/grammars/tasm.tmLanguage.json","/resources/grammars/func.tmLanguage.json"]}}
import { createTonPay } from "@ton-pay/ui/vanilla";

const tonPay = createTonPay({
  manifestUrl: "https://<APP_URL>/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

<AccordionGroup>
  <Accordion title="If the button does not render">
    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
  </Accordion>

  <Accordion title="If the callback is not invoked">
    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
  </Accordion>

  <Accordion title="If import map erros occur">
    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
  </Accordion>

  <Accordion title="If CORS errors occur">
    1. Serve the manifest from the same domain or enable CORS
    2. Use HTTPS in production
    3. Verify that CDN resources are accessible
  </Accordion>
</AccordionGroup>
