Web SDK Overview
The Bahn Web SDK is a browser script that collects payment details inside Bahn-hosted iframes and confirms payments against the Bahn API. Card numbers, expiry dates and CVCs are typed into the iframes and never touch your page or your servers.
This page explains how the pieces fit together and which flow to pick. To write code straight away, go to Getting Started.
How It Works
An integration has three parts:
| Part | Runs on | What it does |
|---|---|---|
| Your backend | Your servers | Creates PaymentIntents with your secret API key, and receives webhooks |
| Your checkout page + Bahn SDK | The shopper's browser | Loads the SDK, mounts the payment fields, and confirms the payment with the client_secret |
| Bahn iframes + API | bn.cake.vn (production) / bn.cakedigibank.tech (sandbox) | Hold the card data, call the Bahn API, and run 3DS challenges |
sequenceDiagram
participant Browser as Checkout page + SDK
participant Backend as Your backend
participant Bahn as Bahn API + iframes
Browser->>Backend: Start checkout
Backend->>Bahn: Create PaymentIntent (API key)
Bahn-->>Backend: PaymentIntent + client_secret
Backend-->>Browser: client_secret
Browser->>Bahn: confirmPayment({ client_secret }) via card iframe
Bahn-->>Browser: payment_intent (+ 3DS payload if needed)
Browser->>Bahn: mount3DS(...) — shopper completes challenge
Bahn-->>Backend: Webhook with the final status
Keys
| Key | Where it's used | Can it be public? |
|---|---|---|
Publishable key (pk) | Passed to new Bahn({ pk }) in the browser | Yes. It only identifies your merchant account. |
| API key | Bn-Api-Key header on server-to-server calls, which are also JWS-signed | No. Never put it in browser code. |
Sandbox and production are separate environments. Use the key issued for the environment you pass to new Bahn({ environment }). Keys are issued during Onboarding.
Core Objects
| Object | What it is |
|---|---|
| PaymentIntent | One payment attempt for a given amount. Your backend creates it. |
client_secret | A per-PaymentIntent secret your backend hands to the browser. The SDK uses it to confirm that one PaymentIntent and nothing else. |
| Confirmation token | A one-time token wrapping the card the shopper entered. Created in the browser with createConfirmationToken() and sent to your backend, which uses it to create and confirm the payment. |
| SetupIntent | Saves a card for later use without charging it. Confirmed with confirmCardSetup(). |
| 3DS session | A 3D Secure challenge the issuer requires. The SDK shows it with mount3DS() or handleNextAction(). |
Choose a Flow
| You want to… | Use | Guide |
|---|---|---|
| Take a card payment for an amount you know up front | Direct confirmation. The backend creates the PaymentIntent, the browser calls confirmPayment(). | Confirm Payment |
| Decide the final amount on your server after seeing the card (discounts, surcharges, fraud checks) | Token-based flow. The browser calls createConfirmationToken(), the backend creates and confirms, then the browser calls handleNextAction(). | Token-Based Flow |
| Save a card without charging it | SetupIntent with confirmCardSetup() | Save a Card |
| Let the shopper pay by scanning a bank QR code | Napas QR with mountPaymentQR() | QR Payments |
| Offer a one-tap wallet button | Apple Pay / Google Pay with mountApplePay() / mountGooglePay() | Apple Pay, Google Pay |
Trust the webhook, not the browser
The browser result tells you what to show the shopper next. Your backend should mark an order as paid only after it receives the webhook for the final status. See Webhooks.
Integration Steps
- Get your keys during Onboarding.
- Load the SDK and mount the card fields. See Getting Started.
- Create PaymentIntents on your backend. See Authentication for how to sign requests.
- Confirm the payment and handle 3DS in the browser. See Confirm Payment and 3DS Authentication.
- Handle webhooks on your backend. See Webhooks.
- Test in sandbox with the sandbox test cards.
- Go live using the Go-Live Checklist.