batpay-sdk
v1.1.7
Published
Official BATPay JavaScript SDK for popup-based account binding and payments
Maintainers
Readme
BATPay JavaScript SDK
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-sdkThen 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";