npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

batpay-sdk

v1.1.7

Published

Official BATPay JavaScript SDK for popup-based account binding and payments

Readme

BATPay JavaScript SDK

npm version npm downloads license

The official BATPay SDK for performing account binding and payment operations using a secure, lightweight, and easy-to-integrate popup window for your website or web app.


Installation

Install via npm

If you’re using a bundler such as Vite or Webpack:

npm install batpay-sdk

Then import and use it in your code:

import BatpaySDK from "batpay-sdk";

via CDN

If you’re not using a bundler, simply include the script in your HTML:

<script src="https://assets-v2.batpay.id/assets/sdk/batpay-sdk.script.js"></script>

<script>
  // SDK is available as a global object
  const { BatpaySDK } = window;
</script>

Overview

The BATPay SDK allows merchants and partners to securely integrate account binding and payment flows through either:

  • POPUP mode (default) — opens a new, centered popup window (or new tab).
  • IFRAME mode — embeds directly into your web page.

Both modes communicate securely with BATPay servers using window.postMessage, with origin validation.


Quick Usage

Example — Account Binding

A quick example showing how to start the Account Binding flow using the SDK.

try {
  const result = await BatpaySDK.openAccountBinding({
    url: redirectUrl,
    onPopupBlocked: "REDIRECT", // fallback if popup blocked
  });

  console.log("✅ Account binding success:", result);
} catch (error) {
  console.error("❌ Account binding failed:", error);
}

Example — Payment

A quick example showing how to start the Payment flow using the SDK.

try {
  const result = await BatpaySDK.openPayment({
    url: redirectUrl,
  });

  console.log("✅ Payment success:", result);
} catch (error) {
  console.error("❌ Payment failed:", error);
}

Example — IFRAME mode

The SDK can also embed the BATPay interface directly inside your web page instead of opening a popup. To do this, set mode: "IFRAME" and provide a container element (or a CSS selector).

<div id="batpay-iframe-container"></div>

<script type="module">
  import BatpaySDK from "batpay-sdk";

  async function startPayment() {
    try {
      const result = await BatpaySDK.openPayment({
        url: redirectUrl,
        mode: "IFRAME", // embed instead of popup
        iframeContainer: document.getElementById("batpay-iframe-container"),
        width: 500,
        height: 700,
      });

      console.log("✅ Payment success:", result);
    } catch (error) {
      console.error("❌ Payment failed:", error);
    }
  }

  startPayment();
</script>

Example using a CSS selector

If you prefer not to reference the element directly, you can also use a CSS selector as the iframe container.

<!-- Your HTML container -->
<div class="batpay-wrapper"></div>

<script type="module">
  import BatpaySDK from "batpay-sdk";

  BatpaySDK.openAccountBinding({
    url: redirectUrl,
    mode: "IFRAME",
    iframeContainer: ".batpay-wrapper", // CSS selector also supported
    width: 600,
    height: 800,
  })
    .then((result) => {
      console.log("✅ Account binding success:", result);
    })
    .catch((error) => {
      console.error("❌ Account binding failed:", error);
    });
</script>

Browser Popup Blocking Behavior

Most modern browsers — especially Safari (on macOS and iOS) — block popup windows that are not directly triggered by a user gesture (like a button click).

If the popup is blocked, the SDK automatically throws a POPUP_BLOCKED error. To handle this gracefully, set the onPopupBlocked option to REDIRECT — this tells the SDK to automatically redirect the current page to the BATPay URL instead of opening a popup.


Options

| Option | Type | Default | Description | | ----------------- | ------------------------- | -------------------- | ---------------------------------------------------------------------------- | | url | string | — | Required. The BATPay page URL. | | mode | "POPUP" | "IFRAME" | "POPUP" | Determines how the SDK opens the BATPay page. | | iframeContainer | HTMLElement | string | — | DOM element or selector to append the iframe (required if mode: 'IFRAME'). | | width | number | 600 | Popup or iframe width in pixels. | | height | number | 800 | Popup or iframe height in pixels. | | name | string | "batpay_sdk_popup" | Name of popup window. | | timeoutMs | number | 600000 (10 min) | Maximum wait time before automatic rejection. | | params | Record<string, string> | {} | Additional query parameters appended to the URL. | | target | "popup" | "_blank" | "popup" | Determines if popup opens centered or as a new tab. | | onPopupBlocked | "ERROR" | "REDIRECT" | "ERROR" | Action when popup is blocked by browser. |


Response Format

When successful, the returned promise resolves with:

interface BatpaySDKResult {
  type: "ACCOUNT_BINDING_SUCCESS" | "PAYMENT_SUCCESS" | "CANCELLED";
  data: {
    from: string;
    redirectUrl: string; // Empty string ("") if type is "CANCELLED"
  };
}

Error Handling

If the process fails, the promise rejects with a BatpaySDKError instance.

class BatpaySDKError extends Error {
  code:
    | "POPUP_BLOCKED"
    | "POPUP_CLOSED"
    | "TIMEOUT"
    | "INVALID_ORIGIN"
    | "MISSING_URL"
    | "MISSING_CONTAINER"
    | "CONTAINER_NOT_FOUND";
  message: string;
}

Error Codes

| Code | Description | | --------------------- | ------------------------------------------------------------------------------------- | | POPUP_BLOCKED | Browser blocked the popup window. | | POPUP_CLOSED | User manually closed the popup before completion. | | TIMEOUT | No message received within the timeout period. | | INVALID_ORIGIN | Message came from an untrusted origin. | | MISSING_URL | Required URL was missing. | | MISSING_CONTAINER | iframeContainer option was not provided in IFRAME mode.           | | CONTAINER_NOT_FOUND | The DOM element or selector provided for iframeContainer was not found.           |

Example

import BatpaySDK, { BatpaySDKError } from "batpay-sdk";

async function handlePayment() {
  try {
    const result = await BatpaySDK.openPayment({
      url: redirectUrl,
    });

    switch (result.type) {
      case "PAYMENT_SUCCESS":
        console.log("✅ Payment success:", result);
        break;
      case "CANCELLED":
        console.warn("⚠️ Operation cancelled by the user.");
        break;
      default:
        console.error("Unexpected result type:", result.type);
    }

    console.log("✅ Payment success:", result);
  } catch (error) {
    if (error instanceof BatpaySDKError) {
      switch (error.code) {
        case "POPUP_BLOCKED":
          console.warn(
            "Popup blocked by browser. Consider using fallback redirect."
          );
          break;
        case "POPUP_CLOSED":
          console.warn("User closed the popup before finishing.");
          break;
        case "TIMEOUT":
          console.warn("Operation timed out. Try again later.");
          break;
        case "INVALID_ORIGIN":
          console.error("Untrusted message origin detected.");
          break;
        case "MISSING_URL":
          console.error("Missing required 'url' parameter.");
        case "MISSING_CONTAINER":
          console.error("IFRAME mode requires 'iframeContainer' option.");
          break;
        case "CONTAINER_NOT_FOUND":
          console.error("Iframe container element not found in the DOM.");
          break;
        default:
          console.error(`Unknown error: ${error.message}`);
      }
    } else {
      // Non-SDK errors (e.g. runtime or network issues)
      console.error("Unexpected error:", error);
    }
  }
}

Type Definitions

type BatpayEventType =
  | "ACCOUNT_BINDING_SUCCESS"
  | "PAYMENT_SUCCESS"
  | "CANCELLED";

type BatpaySDKResultData = {
  from: string;
  redirectUrl: string;
};

interface BatpaySDKOptions {
  url: string;
  mode?: "POPUP" | "IFRAME";
  iframeContainer?: HTMLElement | string;
  width?: number;
  height?: number;
  name?: string;
  timeoutMs?: number;
  params?: Record<string, string>;
  target?: "popup" | "_blank";
  onPopupBlocked?: "ERROR" | "REDIRECT";
}

interface BatpaySDKResult {
  type: BatpayEventType;
  data: BatpaySDKResultData;
}

type BatpaySDKErrorCode =
  | "POPUP_BLOCKED"
  | "POPUP_CLOSED"
  | "TIMEOUT"
  | "INVALID_ORIGIN"
  | "MISSING_URL"
  | "MISSING_CONTAINER"
  | "CONTAINER_NOT_FOUND";

Related Links