SDK Reference
Complete API reference for the Bahn Web SDK. For the full shape of every parameter, result and callback, see Type Definitions — it also has a downloadable bahn.d.ts for TypeScript projects.
Installation
Load the SDK as a plain, version-pinned script — no bundler required:
<script
src="https://bn.cake.vn/bn-sdk/v2.4.0/index.js"
integrity="sha384-jBbonUZLgKU82F+X/ITqcmeInXYYwZYdmCDoPFX8wkWL9dCkeUHyi0Fs1EUnkeDS"
crossorigin="anonymous"
></script>This exposes Bahn as a global (window.Bahn) — no import needed. This is the same script URL for both sandbox and production; only the environment option passed to new Bahn() changes which API/iframe domains it talks to. Each release lives at its own /bn-sdk/v<version>/index.js path with a matching index.js.sha384 SRI hash alongside it. See Getting Started and Environments for details.
Bahn Class
The main SDK class. A singleton — calling new Bahn() a second time returns the existing instance and merges new options.
const bahn = new Bahn(options: BahnOptions);BahnOptions
| Param | Type | Required | Default | Description |
|---|---|---|---|---|
pk | string | Yes | — | Publishable key sent as X-Bn-Publishable-Key header |
environment | "sandbox" | "production" | Yes | — | Target API environment |
appId | string | No | — | Tenant app ID for 3DS routing |
teamId | string | No | — | Tenant team ID for 3DS routing |
paymentIntentPollAttempts | number | No | 10 | Max polling attempts for payment intent status |
Methods
bahn.mountCard(containerId, options?): CardComponent
Mounts the PCI-compliant card input component. See Card Payments for full details.
card.unmount(): void
Removes the card input and cleans up event listeners. Called on the CardComponent returned by mountCard().
card.applyConfig(fields, inputStyle?): void
Re-applies field configuration to mounted iframes without remounting. Called on the CardComponent returned by mountCard().
card.applyStyles(stateStyles): void
Re-applies state-based styles (base/focus/invalid) to mounted iframes without remounting. Called on the CardComponent returned by mountCard(). See Card Payments → State-Based Styling.
bahn.mountPaymentQR(selector, clientSecret, options?): IQRComponent
Mounts a Napas QR code iframe and starts polling. See QR Payments for full details.
qr.unmount(): void
Removes the QR iframe and cleans up. Called on the IQRComponent returned by mountPaymentQR().
bahn.getConfig(): Promise<BahnConfig>
Fetches your merchant's Apple Pay configuration — merchant_name, supported_networks, merchant_capabilities. Not required before calling mountApplePay(), which resolves these same values internally. Call getConfig() directly only if you need these values for something other than mountApplePay() — for example, your own UI. Unlike every other payment method, this is a plain direct fetch — no component needs to be mounted first.
interface BahnConfig {
apple_pay: {
enabled: boolean;
merchant_name: string;
supported_networks: string[];
merchant_capabilities: string[];
};
}bahn.isApplePayAvailable(): Promise<boolean>
Optional pre-flight check for whether the shopper's browser/device can use Apple Pay. mountApplePay() runs this same check internally and simply won't render the button if it fails, so calling this first isn't required — use it only if you want to control your own layout (e.g. hide a whole "Or pay with Apple Pay" section, not just the button) before calling mountApplePay(). This is a client-side check only — it doesn't confirm merchant-level Apple Pay enablement, which surfaces as an "error" event from mountApplePay() at the point the shopper taps the button. A true result on Chrome/Firefox/Edge reflects only that the browser version supports Apple's cross-browser fallback, and requires a separate merchant enrollment with Apple to actually work — see Apple Pay → Browser support.
bahn.mountApplePay(selector, clientSecret, options): IApplePayButtonComponent
Renders an Apple Pay button at selector and manages the full payment sheet lifecycle — merchant validation, authorization, and (if triggered) 3D Secure — internally. The 3D Secure challenge, if triggered on the direct-confirmation flow, mounts on your own page via bahn.mount3DS(). Requires Safari 17 / iOS 17+. Every options field besides amount/currency/country is optional; merchantName/supportedNetworks/merchantCapabilities resolve to your merchant's configured values when omitted. Renders nothing if Apple Pay isn't available — call bahn.isApplePayAvailable() yourself first only if you'd rather hide the entry point entirely than react to an "error" event. See Apple Pay for full details.
clientSecret selects the flow: pass it for direct confirmation ("success"/"error" events); omit it (undefined) for the token-based flow ("token" event with a confirmation_token — send it to your own backend, then call bahn.handleNextAction() with the resulting client_secret, same as card's token-based flow).
options.requestShipping: true collects a shipping address: listen for "shippingcontactselected"/"shippingmethodselected", each firing with { contact | shippingMethod, resolve, reject }; the sheet stays open until you call one of those. See Apple Pay → Collecting a shipping address.
ap.unmount(): void
Removes the Apple Pay button and cleans up. Called on the IApplePayButtonComponent returned by mountApplePay(). bahn.unmountApplePay()/bahn.cleanup() also unmount it.
bahn.isGooglePayAvailable(): Promise<boolean>
Optional pre-flight check for whether the shopper's browser can use Google Pay. mountGooglePay() runs this same check internally and simply won't render the button if it fails, so calling this first isn't required — use it only if you want to control your own layout (e.g. hide a whole "Or pay with Google Pay" section, not just the button) before calling mountGooglePay(). See Google Pay → Browser support.
bahn.mountGooglePay(selector, clientSecret, options): IGooglePayButtonComponent
Renders a Google Pay button at selector and manages the full payment sheet lifecycle — authorization and (if triggered) 3D Secure — internally. The 3D Secure challenge, if triggered on the direct-confirmation flow, mounts on your own page via bahn.mount3DS(). Works in every browser Google Pay supports, including Safari and Firefox. Every options field besides amount/currency/country is optional. Renders nothing if Google Pay isn't available — call bahn.isGooglePayAvailable() yourself first only if you'd rather hide the entry point entirely than react to an "error" event. See Google Pay for full details.
clientSecret selects the flow: pass it for direct confirmation ("success"/"error" events); omit it (undefined) for the token-based flow ("token" event with a confirmation_token — send it to your own backend, then call bahn.handleNextAction() with the resulting client_secret, same as card's token-based flow).
options.requestShipping: true collects a shipping address: listen for "shippingaddresschanged"/"shippingoptionchanged", each firing with { address | shippingOption, resolve, reject }; the sheet stays open until you call one of those. See Google Pay → Collecting a shipping address.
gp.unmount(): void
Removes the Google Pay button and cleans up. Called on the IGooglePayButtonComponent returned by mountGooglePay(). bahn.unmountGooglePay()/bahn.cleanup() also unmount it.
bahn.mount3DS(sessionId, callbacks, options?): IThreeDSecure
Mounts the 3DS challenge modal and returns the component. The modal auto-unmounts on success/failure; call unmount() on the returned component to dismiss it early. See 3DS Authentication for full details.
bahn.getChallengeRedirectUrl(sessionId, returnUrl, options?): string
Builds a full redirect URL to the standalone 3DS challenge page for full-page redirect flows (e.g. from mobile apps, external checkout pages) where an iframe overlay is not possible. The challenge page handles the complete 3DS flow and redirects the user back to returnUrl on completion.
Parameters:
| Param | Type | Required | Description |
|---|---|---|---|
sessionId | string | Yes | 3DS session ID from confirmPayment().three_ds_payload.id |
returnUrl | string | Yes | Where the challenge page redirects back on completion |
options.brandName | string | No | Brand name shown while returning ("Returning to {brandName}…"). Default: "Cake" |
Returns: A fully constructed URL string ready for window.location.href.
const url = bahn.getChallengeRedirectUrl(sessionId, "https://merchant.com/callback", {
brandName: "MyStore",
});
window.location.href = url;See Standalone Challenge Page for the full flow and URL contract.
bahn.confirmPayment(payload): Promise<{ payment_intent, three_ds_payload? }>
Confirms a payment intent via the card-number iframe. Requires mountCard() first. See Confirm Payment for the full flow.
Payload (ConfirmPaymentPayload):
| Field | Type | Required | Description |
|---|---|---|---|
client_secret | string | Yes | Client secret of the payment intent from your backend |
payment_method | { billing_details?: ConfirmationTokenBillingDetails } | No | Optional billing details (card data is merged by the iframe) |
payment_method_options | Record<string, unknown> | No | Provider-specific options |
confirmation_token | string | No | Token from createConfirmationToken() |
amount | string | No | Optional amount override, in the smallest currency unit |
Returns:
| Field | Type | Description |
|---|---|---|
payment_intent | Record<string, unknown> | The PaymentIntent object |
three_ds_payload | ThreeDSPayloadDecoded | undefined | 3DS payload if required |
bahn.confirmCardSetup(payload): Promise<{ setup_intent, three_ds_payload? }>
Confirms a setup intent via the card-number iframe — saves a card without charging it. Requires mountCard() first. See Save a Card.
Payload (ConfirmCardSetupPayload):
| Field | Type | Required | Description |
|---|---|---|---|
client_secret | string | Yes | Client secret of the setup intent from your backend |
payment_method | { billing_details?: ConfirmationTokenBillingDetails } | No | Optional billing details (card data is merged by the iframe) |
payment_method_options | Record<string, unknown> | No | Provider-specific options |
Returns:
| Field | Type | Description |
|---|---|---|
setup_intent | Record<string, unknown> | The SetupIntent object |
three_ds_payload | ThreeDSPayloadDecoded | undefined | 3DS payload if required |
bahn.createConfirmationToken(payload): Promise<ConfirmationTokenResult>
Creates a one-time confirmation token. Requires mountCard() and pk first. See Token-Based Flow.
interface ConfirmationTokenResult {
confirmation_token: string;
}bahn.handleNextAction(input, callbacks): Promise<void>
Handles the next action for a payment intent (3DS, polling, or terminal state). input is either a client_secret string (SDK fetches the payment intent itself, requires mountCard()/mountApplePay(), and polls after 3DS) or a payment_intent object your own backend already returned (skips that fetch, must include client_secret, and never polls — onSuccess/onFailure resolve immediately from the 3DS outcome with the same object, no iframe required; a non-terminal, non-requires_action status calls onError instead of silently doing nothing). See Token-Based Flow → handleNextAction for full details.
bahn.pollPaymentIntentStatus(clientSecret, callbacks): void
Starts polling payment intent status. Call stopPaymentIntentPolling() to cancel. See Token-Based Flow → pollPaymentIntentStatus for full details.
bahn.stopPaymentIntentPolling(): void
Stops any active payment intent polling.
bahn.pollSetupIntentStatus(clientSecret, callbacks): void
Starts polling setup intent status. Call stopSetupIntentPolling() to cancel. See Save a Card.
bahn.stopSetupIntentPolling(): void
Stops any active setup intent polling.
bahn.cleanup(): void
Cleans up all resources: unmounts card, 3DS, QR, and Apple Pay components, and stops payment/setup intent polling.
Singleton Behavior
new Bahn() returns a singleton. Subsequent calls merge new options into the existing instance — existing non-empty values are kept, new values fill gaps. Conflicts are logged as warnings.
// First init
const bahn = new Bahn({ pk: "pk_1", environment: "sandbox" });
// Later — returns same instance, appId is applied to it
const same = new Bahn({ pk: "pk_2", appId: "app_123" });
// pk kept as "pk_1" (existing non-empty), appId set to "app_123" (was empty)
// Warning logged: pk conflict — keeping "pk_1", ignoring "pk_2"window.BahnCake
The singleton is also set on window.BahnCake:
declare global {
interface Window {
BahnCake?: Bahn;
}
}You can access the instance directly:
const bahn = window.BahnCake;
if (bahn) {
bahn.cleanup();
}ThreeDSPayloadDecoded
Shape of the decoded 3DS base64 payload returned by confirmPayment(). Every other SDK type is on Type Definitions.
interface ThreeDSPayloadDecoded {
provider: string; // 3DS provider identifier
app_id: string; // Tenant app ID
team_id: string; // Tenant team ID
id: string; // 3DS session ID — pass to mount3DS()
}